diff --git a/app/build.gradle b/app/build.gradle index d86957b0f..eedd79f25 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,8 +8,8 @@ android { applicationId "net.kdt.pojavlaunch" minSdkVersion 21 targetSdkVersion 26 - versionCode 156220 - versionName "2.4.2pre8b1_6382b_20200331" + versionCode 156230 + versionName "2.4.2_preview10b2_6392b_20200405" } buildTypes { release { diff --git a/app/build/bin/injected/AndroidManifest.xml b/app/build/bin/injected/AndroidManifest.xml index dff0711ac..1fa281534 100644 --- a/app/build/bin/injected/AndroidManifest.xml +++ b/app/build/bin/injected/AndroidManifest.xml @@ -2,8 +2,8 @@ + android:versionCode="156230" + android:versionName="2.4.2_preview10b2_6392b_20200405"> + android:versionCode="156230" + android:versionName="2.4.2_preview10b2_6392b_20200405" > + */ + public static final int control_more3=0x7f0a007c; + public static final int control_more4=0x7f0a007d; public static final int control_mouseoff=0x7f0a0076; public static final int control_mouseon=0x7f0a0077; public static final int control_primary=0x7f0a006b; @@ -2965,7 +2969,7 @@ containing a value of this type. public static final int toast_permission_denied=0x7f0a0046; /** Update part (unused now) */ - public static final int update_console=0x7f0a007d; + public static final int update_console=0x7f0a007e; public static final int warning_action_exit=0x7f0a003c; public static final int warning_action_install=0x7f0a003a; public static final int warning_action_tryanyway=0x7f0a003b; diff --git a/app/build/gen/android/support/v7/appcompat/R.java b/app/build/gen/android/support/v7/appcompat/R.java index 7fe896e3a..24dc271af 100644 --- a/app/build/gen/android/support/v7/appcompat/R.java +++ b/app/build/gen/android/support/v7/appcompat/R.java @@ -2512,7 +2512,7 @@ containing a value of this type. public static final int toggle_log=0x7f020060; } public static final class id { - public static final int action0=0x7f06009b; + public static final int action0=0x7f06009c; public static final int action_bar=0x7f06005d; public static final int action_bar_activity_content=0x7f060002; public static final int action_bar_container=0x7f06005c; @@ -2521,7 +2521,7 @@ containing a value of this type. public static final int action_bar_subtitle=0x7f06003d; public static final int action_bar_title=0x7f06003c; public static final int action_context_bar=0x7f06005e; - public static final int action_divider=0x7f06009f; + public static final int action_divider=0x7f0600a0; public static final int action_menu_divider=0x7f060004; public static final int action_menu_presenter=0x7f060005; public static final int action_mode_bar=0x7f06005a; @@ -2537,12 +2537,12 @@ containing a value of this type. public static final int bottombar_author_logo=0x7f06006d; public static final int bottombar_version_view=0x7f06006c; public static final int buttonPanel=0x7f060046; - public static final int cancel_action=0x7f06009c; + public static final int cancel_action=0x7f06009d; public static final int center=0x7f060011; public static final int center_horizontal=0x7f060012; public static final int center_vertical=0x7f060013; public static final int checkbox=0x7f060054; - public static final int chronometer=0x7f0600a2; + public static final int chronometer=0x7f0600a3; public static final int clip_horizontal=0x7f06001d; public static final int clip_vertical=0x7f06001e; public static final int collapseActionView=0x7f060038; @@ -2552,22 +2552,23 @@ containing a value of this type. public static final int content_log_layout=0x7f060096; public static final int content_log_scroll=0x7f060099; public static final int content_log_toggle_log=0x7f060098; - public static final int control_debug=0x7f0600a8; - public static final int control_down=0x7f0600ae; - public static final int control_inventory=0x7f0600b6; - public static final int control_jump=0x7f0600b2; - public static final int control_keyboard=0x7f0600aa; - public static final int control_left=0x7f0600b0; - public static final int control_listplayers=0x7f0600ad; - public static final int control_mouse_toggle=0x7f0600b7; - public static final int control_primary=0x7f0600b3; - public static final int control_right=0x7f0600b1; - public static final int control_screenshot=0x7f0600ac; - public static final int control_secondary=0x7f0600b4; - public static final int control_shift=0x7f0600b5; - public static final int control_talk=0x7f0600a9; - public static final int control_thirdperson=0x7f0600ab; - public static final int control_up=0x7f0600af; + public static final int content_text_debug=0x7f06009a; + public static final int control_debug=0x7f0600a9; + public static final int control_down=0x7f0600af; + public static final int control_inventory=0x7f0600b7; + public static final int control_jump=0x7f0600b3; + public static final int control_keyboard=0x7f0600ab; + public static final int control_left=0x7f0600b1; + public static final int control_listplayers=0x7f0600ae; + public static final int control_mouse_toggle=0x7f0600b8; + public static final int control_primary=0x7f0600b4; + public static final int control_right=0x7f0600b2; + public static final int control_screenshot=0x7f0600ad; + public static final int control_secondary=0x7f0600b5; + public static final int control_shift=0x7f0600b6; + public static final int control_talk=0x7f0600aa; + public static final int control_thirdperson=0x7f0600ac; + public static final int control_up=0x7f0600b0; public static final int custom=0x7f060052; public static final int customPanel=0x7f060051; public static final int decor_content_parent=0x7f06005b; @@ -2580,7 +2581,7 @@ containing a value of this type. public static final int disableHome=0x7f060028; public static final int edit_query=0x7f06005f; public static final int end=0x7f060014; - public static final int end_padder=0x7f0600a7; + public static final int end_padder=0x7f0600a8; public static final int enterAlways=0x7f06000b; public static final int enterAlwaysCollapsed=0x7f06000c; public static final int exitUntilCollapsed=0x7f06000d; @@ -2595,7 +2596,7 @@ containing a value of this type. public static final int icon=0x7f060044; public static final int ifRoom=0x7f060039; public static final int image=0x7f060041; - public static final int info=0x7f0600a6; + public static final int info=0x7f0600a7; public static final int item_touch_helper_previous_elevation=0x7f060000; public static final int lMTVVer=0x7f060082; public static final int launcherAccEmail=0x7f060077; @@ -2617,8 +2618,8 @@ containing a value of this type. public static final int launcherupdateLogView=0x7f06008a; public static final int launcherupdateProgressBar=0x7f060089; public static final int left=0x7f060016; - public static final int line1=0x7f0600a0; - public static final int line3=0x7f0600a4; + public static final int line1=0x7f0600a1; + public static final int line3=0x7f0600a5; public static final int listMode=0x7f060026; public static final int list_item=0x7f060043; public static final int lmaintabconsoleLogCrashTextView=0x7f06008d; @@ -2629,16 +2630,16 @@ containing a value of this type. public static final int main_game_render_view=0x7f060092; public static final int main_log_behind_GL=0x7f060091; public static final int main_mouse_pointer=0x7f060094; - public static final int main_navigation_view=0x7f06009a; + public static final int main_navigation_view=0x7f06009b; public static final int main_touchpad=0x7f060093; - public static final int media_actions=0x7f06009e; + public static final int media_actions=0x7f06009f; public static final int middle=0x7f060036; public static final int mini=0x7f060022; public static final int multiply=0x7f06002f; - public static final int nav_fixdoubleletters=0x7f0600c5; - public static final int nav_forceclose=0x7f0600c3; - public static final int nav_more3=0x7f0600c6; - public static final int nav_viewlog=0x7f0600c4; + public static final int nav_customkey=0x7f0600c7; + public static final int nav_debug=0x7f0600c6; + public static final int nav_forceclose=0x7f0600c4; + public static final int nav_viewlog=0x7f0600c5; public static final int navigation_header_container=0x7f060072; public static final int never=0x7f06003a; public static final int none=0x7f06001a; @@ -2669,9 +2670,9 @@ containing a value of this type. public static final int search_src_text=0x7f060066; public static final int search_voice_btn=0x7f06006a; public static final int select_dialog_listview=0x7f06006b; - public static final int setting_seektext_progress=0x7f0600b9; - public static final int settings_seekbar_setmaxdxref=0x7f0600b8; - public static final int settings_switch_enablefreeform=0x7f0600ba; + public static final int setting_seektext_progress=0x7f0600ba; + public static final int settings_seekbar_setmaxdxref=0x7f0600b9; + public static final int settings_switch_enablefreeform=0x7f0600bb; public static final int shortcut=0x7f060055; public static final int showCustom=0x7f06002a; public static final int showHome=0x7f06002b; @@ -2685,32 +2686,32 @@ containing a value of this type. public static final int src_in=0x7f060032; public static final int src_over=0x7f060033; public static final int start=0x7f060018; - public static final int startscreenLinearLayout1=0x7f0600bb; - public static final int startscreenProgress=0x7f0600bc; - public static final int status_bar_latest_event_content=0x7f06009d; + public static final int startscreenLinearLayout1=0x7f0600bc; + public static final int startscreenProgress=0x7f0600bd; + public static final int status_bar_latest_event_content=0x7f06009e; public static final int submenuarrow=0x7f060057; public static final int submit_area=0x7f060068; public static final int tabMode=0x7f060027; - public static final int text=0x7f0600a5; - public static final int text2=0x7f0600a3; + public static final int text=0x7f0600a6; + public static final int text2=0x7f0600a4; public static final int textSpacerNoButtons=0x7f06004f; - public static final int time=0x7f0600a1; + public static final int time=0x7f0600a2; public static final int title=0x7f060045; public static final int title_template=0x7f06004a; public static final int top=0x7f060019; public static final int topPanel=0x7f060049; - public static final int topbar_earth_icon=0x7f0600bd; - public static final int topbar_help_text=0x7f0600bf; - public static final int topbar_language_text=0x7f0600be; - public static final int topbar_logo=0x7f0600c0; - public static final int topbar_navmenu_icon=0x7f0600c1; - public static final int topbar_undertop_view=0x7f0600c2; + public static final int topbar_earth_icon=0x7f0600be; + public static final int topbar_help_text=0x7f0600c0; + public static final int topbar_language_text=0x7f0600bf; + public static final int topbar_logo=0x7f0600c1; + public static final int topbar_navmenu_icon=0x7f0600c2; + public static final int topbar_undertop_view=0x7f0600c3; public static final int touch_outside=0x7f06006e; public static final int up=0x7f06000a; public static final int useLogo=0x7f06002d; - public static final int ver_clone=0x7f0600c7; - public static final int ver_edit=0x7f0600c8; - public static final int ver_remove=0x7f0600c9; + public static final int ver_clone=0x7f0600c8; + public static final int ver_edit=0x7f0600c9; + public static final int ver_remove=0x7f0600ca; public static final int view_offset_helper=0x7f060001; public static final int withText=0x7f06003b; public static final int wrap_content=0x7f060034; @@ -2834,10 +2835,11 @@ containing a value of this type. public static final int appbar_scrolling_view_behavior=0x7f0a0000; public static final int bottom_sheet_behavior=0x7f0a0001; public static final int character_counter_pattern=0x7f0a0002; + public static final int control_adebug=0x7f0a007a; public static final int control_chat=0x7f0a0067; + public static final int control_customkey=0x7f0a007b; public static final int control_debug=0x7f0a0068; public static final int control_down=0x7f0a0072; - public static final int control_fixdoubleletters=0x7f0a007a; /** MainActivity: Menu advanced controls */ public static final int control_forceclose=0x7f0a0078; @@ -2848,8 +2850,10 @@ containing a value of this type. public static final int control_keyboard=0x7f0a0066; public static final int control_left=0x7f0a0070; public static final int control_listplayers=0x7f0a0075; - public static final int control_more3=0x7f0a007b; - public static final int control_more4=0x7f0a007c; + /** PointerCapture debug + */ + public static final int control_more3=0x7f0a007c; + public static final int control_more4=0x7f0a007d; public static final int control_mouseoff=0x7f0a0076; public static final int control_mouseon=0x7f0a0077; public static final int control_primary=0x7f0a006b; @@ -2965,7 +2969,7 @@ containing a value of this type. public static final int toast_permission_denied=0x7f0a0046; /** Update part (unused now) */ - public static final int update_console=0x7f0a007d; + public static final int update_console=0x7f0a007e; public static final int warning_action_exit=0x7f0a003c; public static final int warning_action_install=0x7f0a003a; public static final int warning_action_tryanyway=0x7f0a003b; diff --git a/app/build/gen/android/support/v7/recyclerview/R.java b/app/build/gen/android/support/v7/recyclerview/R.java index 314f7cf4c..2e4f0118c 100644 --- a/app/build/gen/android/support/v7/recyclerview/R.java +++ b/app/build/gen/android/support/v7/recyclerview/R.java @@ -2512,7 +2512,7 @@ containing a value of this type. public static final int toggle_log=0x7f020060; } public static final class id { - public static final int action0=0x7f06009b; + public static final int action0=0x7f06009c; public static final int action_bar=0x7f06005d; public static final int action_bar_activity_content=0x7f060002; public static final int action_bar_container=0x7f06005c; @@ -2521,7 +2521,7 @@ containing a value of this type. public static final int action_bar_subtitle=0x7f06003d; public static final int action_bar_title=0x7f06003c; public static final int action_context_bar=0x7f06005e; - public static final int action_divider=0x7f06009f; + public static final int action_divider=0x7f0600a0; public static final int action_menu_divider=0x7f060004; public static final int action_menu_presenter=0x7f060005; public static final int action_mode_bar=0x7f06005a; @@ -2537,12 +2537,12 @@ containing a value of this type. public static final int bottombar_author_logo=0x7f06006d; public static final int bottombar_version_view=0x7f06006c; public static final int buttonPanel=0x7f060046; - public static final int cancel_action=0x7f06009c; + public static final int cancel_action=0x7f06009d; public static final int center=0x7f060011; public static final int center_horizontal=0x7f060012; public static final int center_vertical=0x7f060013; public static final int checkbox=0x7f060054; - public static final int chronometer=0x7f0600a2; + public static final int chronometer=0x7f0600a3; public static final int clip_horizontal=0x7f06001d; public static final int clip_vertical=0x7f06001e; public static final int collapseActionView=0x7f060038; @@ -2552,22 +2552,23 @@ containing a value of this type. public static final int content_log_layout=0x7f060096; public static final int content_log_scroll=0x7f060099; public static final int content_log_toggle_log=0x7f060098; - public static final int control_debug=0x7f0600a8; - public static final int control_down=0x7f0600ae; - public static final int control_inventory=0x7f0600b6; - public static final int control_jump=0x7f0600b2; - public static final int control_keyboard=0x7f0600aa; - public static final int control_left=0x7f0600b0; - public static final int control_listplayers=0x7f0600ad; - public static final int control_mouse_toggle=0x7f0600b7; - public static final int control_primary=0x7f0600b3; - public static final int control_right=0x7f0600b1; - public static final int control_screenshot=0x7f0600ac; - public static final int control_secondary=0x7f0600b4; - public static final int control_shift=0x7f0600b5; - public static final int control_talk=0x7f0600a9; - public static final int control_thirdperson=0x7f0600ab; - public static final int control_up=0x7f0600af; + public static final int content_text_debug=0x7f06009a; + public static final int control_debug=0x7f0600a9; + public static final int control_down=0x7f0600af; + public static final int control_inventory=0x7f0600b7; + public static final int control_jump=0x7f0600b3; + public static final int control_keyboard=0x7f0600ab; + public static final int control_left=0x7f0600b1; + public static final int control_listplayers=0x7f0600ae; + public static final int control_mouse_toggle=0x7f0600b8; + public static final int control_primary=0x7f0600b4; + public static final int control_right=0x7f0600b2; + public static final int control_screenshot=0x7f0600ad; + public static final int control_secondary=0x7f0600b5; + public static final int control_shift=0x7f0600b6; + public static final int control_talk=0x7f0600aa; + public static final int control_thirdperson=0x7f0600ac; + public static final int control_up=0x7f0600b0; public static final int custom=0x7f060052; public static final int customPanel=0x7f060051; public static final int decor_content_parent=0x7f06005b; @@ -2580,7 +2581,7 @@ containing a value of this type. public static final int disableHome=0x7f060028; public static final int edit_query=0x7f06005f; public static final int end=0x7f060014; - public static final int end_padder=0x7f0600a7; + public static final int end_padder=0x7f0600a8; public static final int enterAlways=0x7f06000b; public static final int enterAlwaysCollapsed=0x7f06000c; public static final int exitUntilCollapsed=0x7f06000d; @@ -2595,7 +2596,7 @@ containing a value of this type. public static final int icon=0x7f060044; public static final int ifRoom=0x7f060039; public static final int image=0x7f060041; - public static final int info=0x7f0600a6; + public static final int info=0x7f0600a7; public static final int item_touch_helper_previous_elevation=0x7f060000; public static final int lMTVVer=0x7f060082; public static final int launcherAccEmail=0x7f060077; @@ -2617,8 +2618,8 @@ containing a value of this type. public static final int launcherupdateLogView=0x7f06008a; public static final int launcherupdateProgressBar=0x7f060089; public static final int left=0x7f060016; - public static final int line1=0x7f0600a0; - public static final int line3=0x7f0600a4; + public static final int line1=0x7f0600a1; + public static final int line3=0x7f0600a5; public static final int listMode=0x7f060026; public static final int list_item=0x7f060043; public static final int lmaintabconsoleLogCrashTextView=0x7f06008d; @@ -2629,16 +2630,16 @@ containing a value of this type. public static final int main_game_render_view=0x7f060092; public static final int main_log_behind_GL=0x7f060091; public static final int main_mouse_pointer=0x7f060094; - public static final int main_navigation_view=0x7f06009a; + public static final int main_navigation_view=0x7f06009b; public static final int main_touchpad=0x7f060093; - public static final int media_actions=0x7f06009e; + public static final int media_actions=0x7f06009f; public static final int middle=0x7f060036; public static final int mini=0x7f060022; public static final int multiply=0x7f06002f; - public static final int nav_fixdoubleletters=0x7f0600c5; - public static final int nav_forceclose=0x7f0600c3; - public static final int nav_more3=0x7f0600c6; - public static final int nav_viewlog=0x7f0600c4; + public static final int nav_customkey=0x7f0600c7; + public static final int nav_debug=0x7f0600c6; + public static final int nav_forceclose=0x7f0600c4; + public static final int nav_viewlog=0x7f0600c5; public static final int navigation_header_container=0x7f060072; public static final int never=0x7f06003a; public static final int none=0x7f06001a; @@ -2669,9 +2670,9 @@ containing a value of this type. public static final int search_src_text=0x7f060066; public static final int search_voice_btn=0x7f06006a; public static final int select_dialog_listview=0x7f06006b; - public static final int setting_seektext_progress=0x7f0600b9; - public static final int settings_seekbar_setmaxdxref=0x7f0600b8; - public static final int settings_switch_enablefreeform=0x7f0600ba; + public static final int setting_seektext_progress=0x7f0600ba; + public static final int settings_seekbar_setmaxdxref=0x7f0600b9; + public static final int settings_switch_enablefreeform=0x7f0600bb; public static final int shortcut=0x7f060055; public static final int showCustom=0x7f06002a; public static final int showHome=0x7f06002b; @@ -2685,32 +2686,32 @@ containing a value of this type. public static final int src_in=0x7f060032; public static final int src_over=0x7f060033; public static final int start=0x7f060018; - public static final int startscreenLinearLayout1=0x7f0600bb; - public static final int startscreenProgress=0x7f0600bc; - public static final int status_bar_latest_event_content=0x7f06009d; + public static final int startscreenLinearLayout1=0x7f0600bc; + public static final int startscreenProgress=0x7f0600bd; + public static final int status_bar_latest_event_content=0x7f06009e; public static final int submenuarrow=0x7f060057; public static final int submit_area=0x7f060068; public static final int tabMode=0x7f060027; - public static final int text=0x7f0600a5; - public static final int text2=0x7f0600a3; + public static final int text=0x7f0600a6; + public static final int text2=0x7f0600a4; public static final int textSpacerNoButtons=0x7f06004f; - public static final int time=0x7f0600a1; + public static final int time=0x7f0600a2; public static final int title=0x7f060045; public static final int title_template=0x7f06004a; public static final int top=0x7f060019; public static final int topPanel=0x7f060049; - public static final int topbar_earth_icon=0x7f0600bd; - public static final int topbar_help_text=0x7f0600bf; - public static final int topbar_language_text=0x7f0600be; - public static final int topbar_logo=0x7f0600c0; - public static final int topbar_navmenu_icon=0x7f0600c1; - public static final int topbar_undertop_view=0x7f0600c2; + public static final int topbar_earth_icon=0x7f0600be; + public static final int topbar_help_text=0x7f0600c0; + public static final int topbar_language_text=0x7f0600bf; + public static final int topbar_logo=0x7f0600c1; + public static final int topbar_navmenu_icon=0x7f0600c2; + public static final int topbar_undertop_view=0x7f0600c3; public static final int touch_outside=0x7f06006e; public static final int up=0x7f06000a; public static final int useLogo=0x7f06002d; - public static final int ver_clone=0x7f0600c7; - public static final int ver_edit=0x7f0600c8; - public static final int ver_remove=0x7f0600c9; + public static final int ver_clone=0x7f0600c8; + public static final int ver_edit=0x7f0600c9; + public static final int ver_remove=0x7f0600ca; public static final int view_offset_helper=0x7f060001; public static final int withText=0x7f06003b; public static final int wrap_content=0x7f060034; @@ -2834,10 +2835,11 @@ containing a value of this type. public static final int appbar_scrolling_view_behavior=0x7f0a0000; public static final int bottom_sheet_behavior=0x7f0a0001; public static final int character_counter_pattern=0x7f0a0002; + public static final int control_adebug=0x7f0a007a; public static final int control_chat=0x7f0a0067; + public static final int control_customkey=0x7f0a007b; public static final int control_debug=0x7f0a0068; public static final int control_down=0x7f0a0072; - public static final int control_fixdoubleletters=0x7f0a007a; /** MainActivity: Menu advanced controls */ public static final int control_forceclose=0x7f0a0078; @@ -2848,8 +2850,10 @@ containing a value of this type. public static final int control_keyboard=0x7f0a0066; public static final int control_left=0x7f0a0070; public static final int control_listplayers=0x7f0a0075; - public static final int control_more3=0x7f0a007b; - public static final int control_more4=0x7f0a007c; + /** PointerCapture debug + */ + public static final int control_more3=0x7f0a007c; + public static final int control_more4=0x7f0a007d; public static final int control_mouseoff=0x7f0a0076; public static final int control_mouseon=0x7f0a0077; public static final int control_primary=0x7f0a006b; @@ -2965,7 +2969,7 @@ containing a value of this type. public static final int toast_permission_denied=0x7f0a0046; /** Update part (unused now) */ - public static final int update_console=0x7f0a007d; + public static final int update_console=0x7f0a007e; public static final int warning_action_exit=0x7f0a003c; public static final int warning_action_install=0x7f0a003a; public static final int warning_action_tryanyway=0x7f0a003b; diff --git a/app/build/gen/net/kdt/pojavlaunch/BuildConfig.java b/app/build/gen/net/kdt/pojavlaunch/BuildConfig.java index bb43d4f6d..e69de29bb 100644 --- a/app/build/gen/net/kdt/pojavlaunch/BuildConfig.java +++ b/app/build/gen/net/kdt/pojavlaunch/BuildConfig.java @@ -1,6 +0,0 @@ -/** Automatically generated file. DO NOT MODIFY */ -package net.kdt.pojavlaunch; - -public final class BuildConfig { - public final static boolean DEBUG = true; -} \ No newline at end of file diff --git a/app/build/gen/net/kdt/pojavlaunch/R.java b/app/build/gen/net/kdt/pojavlaunch/R.java index a6eeb4c2e..d10f69217 100644 --- a/app/build/gen/net/kdt/pojavlaunch/R.java +++ b/app/build/gen/net/kdt/pojavlaunch/R.java @@ -2512,7 +2512,7 @@ containing a value of this type. public static final int toggle_log=0x7f020060; } public static final class id { - public static final int action0=0x7f06009b; + public static final int action0=0x7f06009c; public static final int action_bar=0x7f06005d; public static final int action_bar_activity_content=0x7f060002; public static final int action_bar_container=0x7f06005c; @@ -2521,7 +2521,7 @@ containing a value of this type. public static final int action_bar_subtitle=0x7f06003d; public static final int action_bar_title=0x7f06003c; public static final int action_context_bar=0x7f06005e; - public static final int action_divider=0x7f06009f; + public static final int action_divider=0x7f0600a0; public static final int action_menu_divider=0x7f060004; public static final int action_menu_presenter=0x7f060005; public static final int action_mode_bar=0x7f06005a; @@ -2537,12 +2537,12 @@ containing a value of this type. public static final int bottombar_author_logo=0x7f06006d; public static final int bottombar_version_view=0x7f06006c; public static final int buttonPanel=0x7f060046; - public static final int cancel_action=0x7f06009c; + public static final int cancel_action=0x7f06009d; public static final int center=0x7f060011; public static final int center_horizontal=0x7f060012; public static final int center_vertical=0x7f060013; public static final int checkbox=0x7f060054; - public static final int chronometer=0x7f0600a2; + public static final int chronometer=0x7f0600a3; public static final int clip_horizontal=0x7f06001d; public static final int clip_vertical=0x7f06001e; public static final int collapseActionView=0x7f060038; @@ -2552,22 +2552,23 @@ containing a value of this type. public static final int content_log_layout=0x7f060096; public static final int content_log_scroll=0x7f060099; public static final int content_log_toggle_log=0x7f060098; - public static final int control_debug=0x7f0600a8; - public static final int control_down=0x7f0600ae; - public static final int control_inventory=0x7f0600b6; - public static final int control_jump=0x7f0600b2; - public static final int control_keyboard=0x7f0600aa; - public static final int control_left=0x7f0600b0; - public static final int control_listplayers=0x7f0600ad; - public static final int control_mouse_toggle=0x7f0600b7; - public static final int control_primary=0x7f0600b3; - public static final int control_right=0x7f0600b1; - public static final int control_screenshot=0x7f0600ac; - public static final int control_secondary=0x7f0600b4; - public static final int control_shift=0x7f0600b5; - public static final int control_talk=0x7f0600a9; - public static final int control_thirdperson=0x7f0600ab; - public static final int control_up=0x7f0600af; + public static final int content_text_debug=0x7f06009a; + public static final int control_debug=0x7f0600a9; + public static final int control_down=0x7f0600af; + public static final int control_inventory=0x7f0600b7; + public static final int control_jump=0x7f0600b3; + public static final int control_keyboard=0x7f0600ab; + public static final int control_left=0x7f0600b1; + public static final int control_listplayers=0x7f0600ae; + public static final int control_mouse_toggle=0x7f0600b8; + public static final int control_primary=0x7f0600b4; + public static final int control_right=0x7f0600b2; + public static final int control_screenshot=0x7f0600ad; + public static final int control_secondary=0x7f0600b5; + public static final int control_shift=0x7f0600b6; + public static final int control_talk=0x7f0600aa; + public static final int control_thirdperson=0x7f0600ac; + public static final int control_up=0x7f0600b0; public static final int custom=0x7f060052; public static final int customPanel=0x7f060051; public static final int decor_content_parent=0x7f06005b; @@ -2580,7 +2581,7 @@ containing a value of this type. public static final int disableHome=0x7f060028; public static final int edit_query=0x7f06005f; public static final int end=0x7f060014; - public static final int end_padder=0x7f0600a7; + public static final int end_padder=0x7f0600a8; public static final int enterAlways=0x7f06000b; public static final int enterAlwaysCollapsed=0x7f06000c; public static final int exitUntilCollapsed=0x7f06000d; @@ -2595,7 +2596,7 @@ containing a value of this type. public static final int icon=0x7f060044; public static final int ifRoom=0x7f060039; public static final int image=0x7f060041; - public static final int info=0x7f0600a6; + public static final int info=0x7f0600a7; public static final int item_touch_helper_previous_elevation=0x7f060000; public static final int lMTVVer=0x7f060082; public static final int launcherAccEmail=0x7f060077; @@ -2617,8 +2618,8 @@ containing a value of this type. public static final int launcherupdateLogView=0x7f06008a; public static final int launcherupdateProgressBar=0x7f060089; public static final int left=0x7f060016; - public static final int line1=0x7f0600a0; - public static final int line3=0x7f0600a4; + public static final int line1=0x7f0600a1; + public static final int line3=0x7f0600a5; public static final int listMode=0x7f060026; public static final int list_item=0x7f060043; public static final int lmaintabconsoleLogCrashTextView=0x7f06008d; @@ -2629,16 +2630,16 @@ containing a value of this type. public static final int main_game_render_view=0x7f060092; public static final int main_log_behind_GL=0x7f060091; public static final int main_mouse_pointer=0x7f060094; - public static final int main_navigation_view=0x7f06009a; + public static final int main_navigation_view=0x7f06009b; public static final int main_touchpad=0x7f060093; - public static final int media_actions=0x7f06009e; + public static final int media_actions=0x7f06009f; public static final int middle=0x7f060036; public static final int mini=0x7f060022; public static final int multiply=0x7f06002f; - public static final int nav_fixdoubleletters=0x7f0600c5; - public static final int nav_forceclose=0x7f0600c3; - public static final int nav_more3=0x7f0600c6; - public static final int nav_viewlog=0x7f0600c4; + public static final int nav_customkey=0x7f0600c7; + public static final int nav_debug=0x7f0600c6; + public static final int nav_forceclose=0x7f0600c4; + public static final int nav_viewlog=0x7f0600c5; public static final int navigation_header_container=0x7f060072; public static final int never=0x7f06003a; public static final int none=0x7f06001a; @@ -2669,9 +2670,9 @@ containing a value of this type. public static final int search_src_text=0x7f060066; public static final int search_voice_btn=0x7f06006a; public static final int select_dialog_listview=0x7f06006b; - public static final int setting_seektext_progress=0x7f0600b9; - public static final int settings_seekbar_setmaxdxref=0x7f0600b8; - public static final int settings_switch_enablefreeform=0x7f0600ba; + public static final int setting_seektext_progress=0x7f0600ba; + public static final int settings_seekbar_setmaxdxref=0x7f0600b9; + public static final int settings_switch_enablefreeform=0x7f0600bb; public static final int shortcut=0x7f060055; public static final int showCustom=0x7f06002a; public static final int showHome=0x7f06002b; @@ -2685,32 +2686,32 @@ containing a value of this type. public static final int src_in=0x7f060032; public static final int src_over=0x7f060033; public static final int start=0x7f060018; - public static final int startscreenLinearLayout1=0x7f0600bb; - public static final int startscreenProgress=0x7f0600bc; - public static final int status_bar_latest_event_content=0x7f06009d; + public static final int startscreenLinearLayout1=0x7f0600bc; + public static final int startscreenProgress=0x7f0600bd; + public static final int status_bar_latest_event_content=0x7f06009e; public static final int submenuarrow=0x7f060057; public static final int submit_area=0x7f060068; public static final int tabMode=0x7f060027; - public static final int text=0x7f0600a5; - public static final int text2=0x7f0600a3; + public static final int text=0x7f0600a6; + public static final int text2=0x7f0600a4; public static final int textSpacerNoButtons=0x7f06004f; - public static final int time=0x7f0600a1; + public static final int time=0x7f0600a2; public static final int title=0x7f060045; public static final int title_template=0x7f06004a; public static final int top=0x7f060019; public static final int topPanel=0x7f060049; - public static final int topbar_earth_icon=0x7f0600bd; - public static final int topbar_help_text=0x7f0600bf; - public static final int topbar_language_text=0x7f0600be; - public static final int topbar_logo=0x7f0600c0; - public static final int topbar_navmenu_icon=0x7f0600c1; - public static final int topbar_undertop_view=0x7f0600c2; + public static final int topbar_earth_icon=0x7f0600be; + public static final int topbar_help_text=0x7f0600c0; + public static final int topbar_language_text=0x7f0600bf; + public static final int topbar_logo=0x7f0600c1; + public static final int topbar_navmenu_icon=0x7f0600c2; + public static final int topbar_undertop_view=0x7f0600c3; public static final int touch_outside=0x7f06006e; public static final int up=0x7f06000a; public static final int useLogo=0x7f06002d; - public static final int ver_clone=0x7f0600c7; - public static final int ver_edit=0x7f0600c8; - public static final int ver_remove=0x7f0600c9; + public static final int ver_clone=0x7f0600c8; + public static final int ver_edit=0x7f0600c9; + public static final int ver_remove=0x7f0600ca; public static final int view_offset_helper=0x7f060001; public static final int withText=0x7f06003b; public static final int wrap_content=0x7f060034; @@ -2834,10 +2835,11 @@ containing a value of this type. public static final int appbar_scrolling_view_behavior=0x7f0a0000; public static final int bottom_sheet_behavior=0x7f0a0001; public static final int character_counter_pattern=0x7f0a0002; + public static final int control_adebug=0x7f0a007a; public static final int control_chat=0x7f0a0067; + public static final int control_customkey=0x7f0a007b; public static final int control_debug=0x7f0a0068; public static final int control_down=0x7f0a0072; - public static final int control_fixdoubleletters=0x7f0a007a; /** MainActivity: Menu advanced controls */ public static final int control_forceclose=0x7f0a0078; @@ -2848,8 +2850,10 @@ containing a value of this type. public static final int control_keyboard=0x7f0a0066; public static final int control_left=0x7f0a0070; public static final int control_listplayers=0x7f0a0075; - public static final int control_more3=0x7f0a007b; - public static final int control_more4=0x7f0a007c; + /** PointerCapture debug + */ + public static final int control_more3=0x7f0a007c; + public static final int control_more4=0x7f0a007d; public static final int control_mouseoff=0x7f0a0076; public static final int control_mouseon=0x7f0a0077; public static final int control_primary=0x7f0a006b; @@ -2965,7 +2969,7 @@ containing a value of this type. public static final int toast_permission_denied=0x7f0a0046; /** Update part (unused now) */ - public static final int update_console=0x7f0a007d; + public static final int update_console=0x7f0a007e; public static final int warning_action_exit=0x7f0a003c; public static final int warning_action_install=0x7f0a003a; public static final int warning_action_tryanyway=0x7f0a003b; diff --git a/app/libs/boardwalk_lwjgl.jar b/app/libs/boardwalk_lwjgl.jar index bd6712008..573c40271 100644 Binary files a/app/libs/boardwalk_lwjgl.jar and b/app/libs/boardwalk_lwjgl.jar differ diff --git a/app/src/main/assets/optifine_patch/AndroidInstaller.class.patch b/app/src/main/assets/optifine_patch/AndroidInstaller.class.patch index 5cf06f9bc..678389256 100644 Binary files a/app/src/main/assets/optifine_patch/AndroidInstaller.class.patch and b/app/src/main/assets/optifine_patch/AndroidInstaller.class.patch differ diff --git a/app/src/main/java/com/android/internal/awt/AndroidGraphics2D.java b/app/src/main/java/com/android/internal/awt/AndroidGraphics2D.java new file mode 100644 index 000000000..78f8e42e5 --- /dev/null +++ b/app/src/main/java/com/android/internal/awt/AndroidGraphics2D.java @@ -0,0 +1,1355 @@ +/* + * Copyright 2007, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.awt; + +import com.android.internal.awt.AndroidGraphicsConfiguration; +// import com.android.internal.graphics.NativeUtils; + +import java.awt.AlphaComposite; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.Image; +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.awt.geom.GeneralPath; +import java.awt.geom.NoninvertibleTransformException; +import java.awt.geom.PathIterator; +import java.awt.image.AffineTransformOp; +import java.awt.image.BufferedImage; +import java.awt.image.BufferedImageOp; +import java.awt.image.DataBuffer; +import java.awt.image.DirectColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.Raster; +import java.awt.image.RenderedImage; +import java.awt.image.SinglePixelPackedSampleModel; +import java.awt.image.WritableRaster; +import java.awt.image.renderable.RenderableImage; +import java.text.AttributedCharacterIterator; +import java.util.Map; + +import org.apache.harmony.awt.gl.ImageSurface; +import org.apache.harmony.awt.gl.MultiRectArea; +import org.apache.harmony.awt.gl.Surface; +import org.apache.harmony.awt.gl.font.AndroidGlyphVector; +import org.apache.harmony.awt.gl.font.FontMetricsImpl; +import org.apache.harmony.awt.gl.image.OffscreenImage; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Path; + +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Region; +import android.graphics.Typeface; +import android.graphics.PixelXorXfermode; +import android.view.Display; +import android.view.WindowManager; +import android.content.Context; + +public class AndroidGraphics2D extends Graphics2D { + + private int displayWidth, displayHeight; + + protected Surface dstSurf = null; + protected MultiRectArea clip = null; + + protected Composite composite = AlphaComposite.SrcOver; + protected AffineTransform transform = new AffineTransform(); + + private static AndroidGraphics2D mAg; + private static Canvas mC; + + // Android Paint + public static Paint mP; + + private static java.awt.Font mFnt; + + // Cached Matrix + public static Matrix mM; + private static FontMetrics mFm; + private static RenderingHints mRh; + private static Color mBc; + + private Area mCurrClip; + + public final static double RAD_360 = Math.PI / 180 * 360; + + // Image drawing + private AndroidJavaBlitter blitter; + private DirectColorModel cm; + private SinglePixelPackedSampleModel sm; + private WritableRaster wr; + + + public static AndroidGraphics2D getInstance() { + if (mAg == null) { + throw new RuntimeException("AndroidGraphics2D not instantiated!"); + } + return mAg; + } + + public static AndroidGraphics2D getInstance(Context ctx, Canvas c, Paint p) { + if (c == null || ctx == null) { + throw new RuntimeException( + "Illegal argument, Canvas cannot be null!"); + } + mAg = new AndroidGraphics2D(ctx, c, p); + return mAg; + } + + private AndroidGraphics2D(Context ctx, Canvas c, Paint p) { + super(); + mC = c; + mP = p; + mM = new Matrix(); + mM.reset(); + mM = mC.getMatrix(); + Rect r = mC.getClipBounds(); + int cl[] = {-1, r.top, r.left, -2, r.top, r.right, -2, r.bottom, r.right, -2, r.bottom, r.left}; + mCurrClip = new Area(createShape(cl)); + if(ctx != null) { + WindowManager wm = (WindowManager)ctx.getSystemService(Context.WINDOW_SERVICE); + Display d = wm.getDefaultDisplay(); + displayWidth = d.getWidth(); + displayHeight = d.getHeight(); + } + blitter = new AndroidJavaBlitter(c); + cm = new DirectColorModel(32, 0xff0000, 0xff00, 0xff, 0xff000000); + sm = new SinglePixelPackedSampleModel( + DataBuffer.TYPE_INT, displayWidth, displayHeight, cm.getMasks()); + wr = Raster.createWritableRaster(sm, null); + dstSurf = new ImageSurface(cm, wr); + } + + @Override + public void addRenderingHints(Map hints) { + if (mRh == null) { + mRh = (RenderingHints) hints; + } + mRh.add((RenderingHints) hints); + } + + public float[] getMatrix() { + float[] f = new float[9]; + mC.getMatrix().getValues(f); + return f; + } + + /** + * + * @return a Matrix in Android format + */ + public float[] getInverseMatrix() { + AffineTransform af = new AffineTransform(createAWTMatrix(getMatrix())); + try { + af = af.createInverse(); + } catch (NoninvertibleTransformException e) { + } + return createMatrix(af); + } + + private Path getPath(Shape s) { + Path path = new Path(); + PathIterator pi = s.getPathIterator(null); + while (pi.isDone() == false) { + getCurrentSegment(pi, path); + pi.next(); + } + return path; + } + + private void getCurrentSegment(PathIterator pi, Path path) { + float[] coordinates = new float[6]; + int type = pi.currentSegment(coordinates); + switch (type) { + case PathIterator.SEG_MOVETO: + path.moveTo(coordinates[0], coordinates[1]); + break; + case PathIterator.SEG_LINETO: + path.lineTo(coordinates[0], coordinates[1]); + break; + case PathIterator.SEG_QUADTO: + path.quadTo(coordinates[0], coordinates[1], coordinates[2], + coordinates[3]); + break; + case PathIterator.SEG_CUBICTO: + path.cubicTo(coordinates[0], coordinates[1], coordinates[2], + coordinates[3], coordinates[4], coordinates[5]); + break; + case PathIterator.SEG_CLOSE: + path.close(); + break; + default: + break; + } + } + + private Shape createShape(int[] arr) { + Shape s = new GeneralPath(); + for(int i = 0; i < arr.length; i++) { + int type = arr[i]; + switch (type) { + case -1: + //MOVETO + ((GeneralPath)s).moveTo(arr[++i], arr[++i]); + break; + case -2: + //LINETO + ((GeneralPath)s).lineTo(arr[++i], arr[++i]); + break; + case -3: + //QUADTO + ((GeneralPath)s).quadTo(arr[++i], arr[++i], arr[++i], + arr[++i]); + break; + case -4: + //CUBICTO + ((GeneralPath)s).curveTo(arr[++i], arr[++i], arr[++i], + arr[++i], arr[++i], arr[++i]); + break; + case -5: + //CLOSE + return s; + default: + break; + } + } + return s; + } + /* + public int[] getPixels() { + return mC.getPixels(); + }*/ + + public static float getRadian(float degree) { + return (float) ((Math.PI / 180) * degree); + } + + private Shape getShape() { + return null; + } + + public static float getDegree(float radian) { + return (float) ((180 / Math.PI) * radian); + } + + /* + * Degree in radian + */ + public static float getEllipsisX(float degree, float princAxis) { + return (float) Math.cos(degree) * princAxis; + } + + public static float getEllipsisY(float degree, float conAxis) { + return (float) Math.sin(degree) * conAxis; + } + + @Override + public void clip(Shape s) { + mC.clipPath(getPath(s)); + } + + public void setCanvas(Canvas c) { + mC = c; + } + + @Override + public void draw(Shape s) { + if (mP == null) { + mP = new Paint(); + } + Paint.Style tmp = mP.getStyle(); + mP.setStyle(Paint.Style.STROKE); + mC.drawPath(getPath(s), mP); + mP.setStyle(tmp); + } +/* + private ArrayList getSegments(Shape s) { + ArrayList arr = new ArrayList(); + PathIterator pi = s.getPathIterator(null); + while (pi.isDone() == false) { + getCurrentSegment(pi, arr); + pi.next(); + } + return arr; + } + + private void getCurrentSegment(PathIterator pi, ArrayList arr) { + float[] coordinates = new float[6]; + int type = pi.currentSegment(coordinates); + switch (type) { + case PathIterator.SEG_MOVETO: + arr.add(new Integer(-1)); + break; + case PathIterator.SEG_LINETO: + arr.add(new Integer(-2)); + break; + case PathIterator.SEG_QUADTO: + arr.add(new Integer(-3)); + break; + case PathIterator.SEG_CUBICTO: + arr.add(new Integer(-4)); + break; + case PathIterator.SEG_CLOSE: + arr.add(new Integer(-5)); + break; + default: + break; + } + } +*/ + /* + * Convenience method, not standard AWT + */ + public void draw(Path s) { + if (mP == null) { + mP = new Paint(); + } + Paint.Style tmp = mP.getStyle(); + mP.setStyle(Paint.Style.STROKE); + s.transform(mM); + mC.drawPath(s, mP); + mP.setStyle(tmp); + } + + @Override + public void drawGlyphVector(GlyphVector g, float x, float y) { + // TODO draw at x, y + // draw(g.getOutline()); + /* + Matrix matrix = new Matrix(); + matrix.setTranslate(x, y); + Path pth = getPath(g.getOutline()); + pth.transform(matrix); + draw(pth); + */ + Path path = new Path(); + char[] c = ((AndroidGlyphVector)g).getGlyphs(); + mP.getTextPath(c, 0, c.length, x, y, path); + mC.drawPath(path, mP); + } + + @Override + public void drawRenderableImage(RenderableImage img, AffineTransform xform) { + throw new RuntimeException("Not implemented!"); + } + + @Override + public void drawRenderedImage(RenderedImage img, AffineTransform xform) { + throw new RuntimeException("Not implemented!"); + } + + @Override + public void drawString(AttributedCharacterIterator iterator, float x, + float y) { + throw new RuntimeException("AttributedCharacterIterator not supported!"); + + } + + @Override + public void drawString(AttributedCharacterIterator iterator, int x, int y) { + throw new RuntimeException("AttributedCharacterIterator not supported!"); + + } + + @Override + public void drawString(String s, float x, float y) { + if (mP == null) { + mP = new Paint(); + } + Paint.Style tmp = mP.getStyle(); + + mP.setStyle(Paint.Style.FILL); + Path pth = new Path(); + mP.getTextPath(s, 0, s.length(), x, y, pth); + mC.drawPath(pth, mP); + mP.setStyle(tmp); + } + + @Override + public void drawString(String str, int x, int y) { + if (mP == null) { + mP = new Paint(); + } + Paint.Style tmp = mP.getStyle(); + mP.setStrokeWidth(0); + + mC.drawText(str.toCharArray(), 0, str.toCharArray().length, x, y, + mP); + mP.setStyle(tmp); + } + + @Override + public void fill(Shape s) { + if (mP == null) { + mP = new Paint(); + } + Paint.Style tmp = mP.getStyle(); + mP.setStyle(Paint.Style.FILL); + mC.drawPath(getPath(s), mP); + mP.setStyle(tmp); + } + + @Override + public Color getBackground() { + return mBc; + } + + @Override + public Composite getComposite() { + throw new RuntimeException("Composite not implemented!"); + } + + @Override + public GraphicsConfiguration getDeviceConfiguration() { + return new AndroidGraphicsConfiguration(); + } + + @Override + public FontRenderContext getFontRenderContext() { + return new FontRenderContext(getTransform(), mP.isAntiAlias(), true); + } + + @Override + public java.awt.Paint getPaint() { + throw new RuntimeException("AWT Paint not implemented in Android!"); + } + + public static Canvas getAndroidCanvas() { + return mC; + } + + public static Paint getAndroidPaint() { + return mP; + } + + @Override + public RenderingHints getRenderingHints() { + return mRh; + } + + @Override + public Stroke getStroke() { + if (mP != null) { + return new BasicStroke(mP.getStrokeWidth(), mP.getStrokeCap() + .ordinal(), mP.getStrokeJoin().ordinal()); + } + return null; + } + + @Override + public AffineTransform getTransform() { + return new AffineTransform(createAWTMatrix(getMatrix())); + } + + @Override + public boolean hit(Rectangle rect, Shape s, boolean onStroke) { + // ???AWT TODO check if on stroke + return s.intersects(rect.getX(), rect.getY(), rect.getWidth(), rect + .getHeight()); + } + + @Override + public void rotate(double theta) { + mM.preRotate((float) AndroidGraphics2D + .getDegree((float) (RAD_360 - theta))); + mC.concat(mM); + } + + @Override + public void rotate(double theta, double x, double y) { + mM.preRotate((float) AndroidGraphics2D.getDegree((float) theta), + (float) x, (float) y); + mC.concat(mM); + } + + @Override + public void scale(double sx, double sy) { + mM.setScale((float) sx, (float) sy); + mC.concat(mM); + } + + @Override + public void setBackground(Color color) { + mBc = color; + mC.clipRect(new Rect(0, 0, mC.getWidth(), mC.getHeight())); + // TODO don't limit to current clip + mC.drawARGB(color.getAlpha(), color.getRed(), color.getGreen(), color + .getBlue()); + } + + @Override + public void setComposite(Composite comp) { + throw new RuntimeException("Composite not implemented!"); + } + + public void setSpaint(Paint paint) { + mP = paint; + } + + @Override + public void setPaint(java.awt.Paint paint) { + setColor((Color)paint); + } + + @Override + public Object getRenderingHint(RenderingHints.Key key) { + if (mRh == null) { + return null; + } + return mRh.get(key); + } + + @Override + public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue) { + if (mRh == null) { + mRh = new RenderingHints(hintKey, hintValue); + } else { + mRh.put(hintKey, hintValue); + } + applyHints(); + } + + @Override + public void setRenderingHints(Map hints) { + mRh = (RenderingHints) hints; + applyHints(); + } + + private void applyHints() { + Object o; + + // TODO do something like this: + /* + * Set s = mRh.keySet(); Iterator it = s.iterator(); while(it.hasNext()) { + * o = it.next(); } + */ + + // ///////////////////////////////////////////////////////////////////// + // not supported in skia + /* + * o = mRh.get(RenderingHints.KEY_ALPHA_INTERPOLATION); if + * (o.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT)) { } else + * if (o.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY)) { } + * else if (o.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED)) { } + * + * o = mRh.get(RenderingHints.KEY_COLOR_RENDERING); if + * (o.equals(RenderingHints.VALUE_COLOR_RENDER_DEFAULT)) { } else if + * (o.equals(RenderingHints.VALUE_COLOR_RENDER_QUALITY)) { } else if + * (o.equals(RenderingHints.VALUE_COLOR_RENDER_SPEED)) { } + * + * o = mRh.get(RenderingHints.KEY_DITHERING); if + * (o.equals(RenderingHints.VALUE_DITHER_DEFAULT)) { } else if + * (o.equals(RenderingHints.VALUE_DITHER_DISABLE)) { } else if + * (o.equals(RenderingHints.VALUE_DITHER_ENABLE)) { } + * + * o = mRh.get(RenderingHints.KEY_FRACTIONALMETRICS); if + * (o.equals(RenderingHints.VALUE_FRACTIONALMETRICS_DEFAULT)) { } else + * if (o.equals(RenderingHints.VALUE_FRACTIONALMETRICS_OFF)) { } else if + * (o.equals(RenderingHints.VALUE_FRACTIONALMETRICS_ON)) { } + * + * o = mRh.get(RenderingHints.KEY_INTERPOLATION); if + * (o.equals(RenderingHints.VALUE_INTERPOLATION_BICUBIC)) { } else if + * (o.equals(RenderingHints.VALUE_INTERPOLATION_BILINEAR)) { } else if + * (o .equals(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR)) { } + * + * o = mRh.get(RenderingHints.KEY_RENDERING); if + * (o.equals(RenderingHints.VALUE_RENDER_DEFAULT)) { } else if + * (o.equals(RenderingHints.VALUE_RENDER_QUALITY)) { } else if + * (o.equals(RenderingHints.VALUE_RENDER_SPEED)) { } + * + * o = mRh.get(RenderingHints.KEY_STROKE_CONTROL); if + * (o.equals(RenderingHints.VALUE_STROKE_DEFAULT)) { } else if + * (o.equals(RenderingHints.VALUE_STROKE_NORMALIZE)) { } else if + * (o.equals(RenderingHints.VALUE_STROKE_PURE)) { } + */ + + o = mRh.get(RenderingHints.KEY_ANTIALIASING); + if (o != null) { + if (o.equals(RenderingHints.VALUE_ANTIALIAS_DEFAULT)) { + mP.setAntiAlias(false); + } else if (o.equals(RenderingHints.VALUE_ANTIALIAS_OFF)) { + mP.setAntiAlias(false); + } else if (o.equals(RenderingHints.VALUE_ANTIALIAS_ON)) { + mP.setAntiAlias(true); + } + } + + o = mRh.get(RenderingHints.KEY_TEXT_ANTIALIASING); + if (o != null) { + if (o.equals(RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT)) { + mP.setAntiAlias(false); + } else if (o.equals(RenderingHints.VALUE_TEXT_ANTIALIAS_OFF)) { + mP.setAntiAlias(false); + } else if (o.equals(RenderingHints.VALUE_TEXT_ANTIALIAS_ON)) { + mP.setAntiAlias(true); + } + } + } + + @Override + public void setStroke(Stroke s) { + if (mP == null) { + mP = new Paint(); + } + BasicStroke bs = (BasicStroke) s; + mP.setStyle(Paint.Style.STROKE); + mP.setStrokeWidth(bs.getLineWidth()); + + int cap = bs.getEndCap(); + if (cap == 0) { + mP.setStrokeCap(Paint.Cap.BUTT); + } else if (cap == 1) { + mP.setStrokeCap(Paint.Cap.ROUND); + } else if (cap == 2) { + mP.setStrokeCap(Paint.Cap.SQUARE); + } + + int join = bs.getLineJoin(); + if (join == 0) { + mP.setStrokeJoin(Paint.Join.MITER); + } else if (join == 1) { + mP.setStrokeJoin(Paint.Join.ROUND); + } else if (join == 2) { + mP.setStrokeJoin(Paint.Join.BEVEL); + } + } + + public static float[] createMatrix(AffineTransform Tx) { + double[] at = new double[9]; + Tx.getMatrix(at); + float[] f = new float[at.length]; + f[0] = (float) at[0]; + f[1] = (float) at[2]; + f[2] = (float) at[4]; + f[3] = (float) at[1]; + f[4] = (float) at[3]; + f[5] = (float) at[5]; + f[6] = 0; + f[7] = 0; + f[8] = 1; + return f; + } + + private float[] createAWTMatrix(float[] matrix) { + float[] at = new float[9]; + at[0] = matrix[0]; + at[1] = matrix[3]; + at[2] = matrix[1]; + at[3] = matrix[4]; + at[4] = matrix[2]; + at[5] = matrix[5]; + at[6] = 0; + at[7] = 0; + at[8] = 1; + return at; + } + + public static Matrix createMatrixObj(AffineTransform Tx) { + Matrix m = new Matrix(); + m.reset(); + m.setValues(createMatrix(Tx)); + return m; + } + + @Override + public void setTransform(AffineTransform Tx) { + mM.reset(); + /* + * if(Tx.isIdentity()) { mM = new Matrix(); } + */ + mM.setValues(createMatrix(Tx)); + Matrix m = new Matrix(); + m.setValues(getInverseMatrix()); + mC.concat(m); + mC.concat(mM); + } + + @Override + public void shear(double shx, double shy) { + mM.setSkew((float) shx, (float) shy); + mC.concat(mM); + } + + @Override + public void transform(AffineTransform Tx) { + Matrix m = new Matrix(); + m.setValues(createMatrix(Tx)); + mC.concat(m); + } + + @Override + public void translate(double tx, double ty) { + mM.setTranslate((float) tx, (float) ty); + mC.concat(mM); + } + + @Override + public void translate(int x, int y) { + mM.setTranslate((float) x, (float) y); + mC.concat(mM); + } + + @Override + public void clearRect(int x, int y, int width, int height) { + mC.clipRect(x, y, x + width, y + height); + if (mBc != null) { + mC.drawARGB(mBc.getAlpha(), mBc.getBlue(), mBc.getGreen(), mBc + .getRed()); + } else { + mC.drawARGB(0xff, 0xff, 0xff, 0xff); + } + } + + @Override + public void clipRect(int x, int y, int width, int height) { + int cl[] = {-1, x, y, -2, x, y + width, -2, x + height, y + width, -2, x + height, y}; + Shape shp = createShape(cl); + mCurrClip.intersect(new Area(shp)); + mC.clipRect(new Rect(x, y, x + width, y + height), Region.Op.INTERSECT); + } + + @Override + public void copyArea(int sx, int sy, int width, int height, int dx, int dy) { + copyArea(mC, sx, sy, width + dx, height + dy, dx, dy); + } + + @Override + public Graphics create() { + return this; + } + + @Override + public void dispose() { + // mC = null; + mP = null; + } + + @Override + public void drawArc(int x, int y, int width, int height, int sa, int ea) { + if (mP == null) { + mP = new Paint(); + } + mP.setStrokeWidth(0); + mC.drawArc(new RectF(x, y, x + width, y + height), 360 - (ea + sa), + ea, true, mP); + } + + + // ???AWT: only used for debuging, delete in final version + public void drawBitmap(Bitmap bm, float x, float y, Paint p) { + mC.drawBitmap(bm, x, y, null); + } + + @Override + public boolean drawImage(Image image, int x, int y, Color bgcolor, + ImageObserver imageObserver) { + + if(image == null) { + return true; + } + + boolean done = false; + boolean somebits = false; + Surface srcSurf = null; + if(image instanceof OffscreenImage){ + OffscreenImage oi = (OffscreenImage) image; + if((oi.getState() & ImageObserver.ERROR) != 0) { + return false; + } + done = oi.prepareImage(imageObserver); + somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0; + srcSurf = oi.getImageSurface(); + }else{ + done = true; + srcSurf = Surface.getImageSurface(image); + } + + if(done || somebits) { + int w = srcSurf.getWidth(); + int h = srcSurf.getHeight(); + + blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h, (AffineTransform) transform.clone(), + composite, bgcolor, clip); + } + return done; + } + + @Override + public boolean drawImage(Image image, int x, int y, ImageObserver imageObserver) { + return drawImage(image, x, y, null, imageObserver); + } + + @Override + public boolean drawImage(Image image, int x, int y, int width, int height, + Color bgcolor, ImageObserver imageObserver) { + + if(image == null) { + return true; + } + if(width == 0 || height == 0) { + return true; + } + + boolean done = false; + boolean somebits = false; + Surface srcSurf = null; + + if(image instanceof OffscreenImage){ + OffscreenImage oi = (OffscreenImage) image; + if((oi.getState() & ImageObserver.ERROR) != 0) { + return false; + } + done = oi.prepareImage(imageObserver); + somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0; + srcSurf = oi.getImageSurface(); + }else{ + done = true; + srcSurf = Surface.getImageSurface(image); + } + + if(done || somebits) { + int w = srcSurf.getWidth(); + int h = srcSurf.getHeight(); + if(w == width && h == height){ + blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h, + (AffineTransform) transform.clone(), + composite, bgcolor, clip); + }else{ + AffineTransform xform = new AffineTransform(); + xform.setToScale((float)width / w, (float)height / h); + blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h, + (AffineTransform) transform.clone(), + xform, composite, bgcolor, clip); + } + } + return done; + } + + @Override + public boolean drawImage(Image image, int x, int y, int width, int height, + ImageObserver imageObserver) { + return drawImage(image, x, y, width, height, null, imageObserver); + } + + @Override + public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, Color bgcolor, + ImageObserver imageObserver) { + + if(image == null) { + return true; + } + if(dx1 == dx2 || dy1 == dy2 || sx1 == sx2 || sy1 == sy2) { + return true; + } + + boolean done = false; + boolean somebits = false; + Surface srcSurf = null; + if(image instanceof OffscreenImage){ + OffscreenImage oi = (OffscreenImage) image; + if((oi.getState() & ImageObserver.ERROR) != 0) { + return false; + } + done = oi.prepareImage(imageObserver); + somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0; + srcSurf = oi.getImageSurface(); + }else{ + done = true; + srcSurf = Surface.getImageSurface(image); + } + + if(done || somebits) { + + int dstX = dx1; + int dstY = dy1; + int srcX = sx1; + int srcY = sy1; + + int dstW = dx2 - dx1; + int dstH = dy2 - dy1; + int srcW = sx2 - sx1; + int srcH = sy2 - sy1; + + if(srcW == dstW && srcH == dstH){ + blitter.blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, srcW, srcH, + (AffineTransform) transform.clone(), + composite, bgcolor, clip); + }else{ + AffineTransform xform = new AffineTransform(); + xform.setToScale((float)dstW / srcW, (float)dstH / srcH); + blitter.blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, srcW, srcH, + (AffineTransform) transform.clone(), + xform, composite, bgcolor, clip); + } + } + return done; + } + + @Override + public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, ImageObserver imageObserver) { + + return drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null, + imageObserver); + } + + @Override + public void drawImage(BufferedImage bufImage, BufferedImageOp op, + int x, int y) { + + if(bufImage == null) { + return; + } + + if(op == null) { + drawImage(bufImage, x, y, null); + } else if(op instanceof AffineTransformOp){ + AffineTransformOp atop = (AffineTransformOp) op; + AffineTransform xform = atop.getTransform(); + Surface srcSurf = Surface.getImageSurface(bufImage); + int w = srcSurf.getWidth(); + int h = srcSurf.getHeight(); + blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h, + (AffineTransform) transform.clone(), xform, + composite, null, clip); + } else { + bufImage = op.filter(bufImage, null); + Surface srcSurf = Surface.getImageSurface(bufImage); + int w = srcSurf.getWidth(); + int h = srcSurf.getHeight(); + blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h, + (AffineTransform) transform.clone(), + composite, null, clip); + } + } + + @Override + public boolean drawImage(Image image, AffineTransform trans, + ImageObserver imageObserver) { + + if(image == null) { + return true; + } + if(trans == null || trans.isIdentity()) { + return drawImage(image, 0, 0, imageObserver); + } + + boolean done = false; + boolean somebits = false; + Surface srcSurf = null; + if(image instanceof OffscreenImage){ + OffscreenImage oi = (OffscreenImage) image; + if((oi.getState() & ImageObserver.ERROR) != 0) { + return false; + } + done = oi.prepareImage(imageObserver); + somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0; + srcSurf = oi.getImageSurface(); + }else{ + done = true; + srcSurf = Surface.getImageSurface(image); + } + + if(done || somebits) { + int w = srcSurf.getWidth(); + int h = srcSurf.getHeight(); + AffineTransform xform = (AffineTransform) transform.clone(); + xform.concatenate(trans); + blitter.blit(0, 0, srcSurf, 0, 0, dstSurf, w, h, xform, composite, + null, clip); + } + return done; + } + + @Override + public void drawLine(int x1, int y1, int x2, int y2) { + if (mP == null) { + mP = new Paint(); + } + mC.drawLine(x1, y1, x2, y2, mP); + } + + @Override + public void drawOval(int x, int y, int width, int height) { + if (mP == null) { + mP = new Paint(); + } + mP.setStyle(Paint.Style.STROKE); + mC.drawOval(new RectF(x, y, x + width, y + height), mP); + } + + @Override + public void drawPolygon(int[] xpoints, int[] ypoints, int npoints) { + if (mP == null) { + mP = new Paint(); + } + mC.drawLine(xpoints[npoints - 1], ypoints[npoints - 1], xpoints[0], + ypoints[0], mP); + for (int i = 0; i < npoints - 1; i++) { + mC.drawLine(xpoints[i], ypoints[i], xpoints[i + 1], + ypoints[i + 1], mP); + } + } + + @Override + public void drawPolyline(int[] xpoints, int[] ypoints, int npoints) { + for (int i = 0; i < npoints - 1; i++) { + drawLine(xpoints[i], ypoints[i], xpoints[i + 1], ypoints[i + 1]); + } + + } + + @Override + public void drawRoundRect(int x, int y, int width, int height, + int arcWidth, int arcHeight) { + if (mP == null) { + mP = new Paint(); + } + mC.drawRoundRect(new RectF(x, y, width, height), arcWidth, + arcHeight, mP); + } + + @Override + public void fillArc(int x, int y, int width, int height, int sa, int ea) { + if (mP == null) { + mP = new Paint(); + } + + Paint.Style tmp = mP.getStyle(); + mP.setStyle(Paint.Style.FILL_AND_STROKE); + mC.drawArc(new RectF(x, y, x + width, y + height), 360 - (sa + ea), + ea, true, mP); + + mP.setStyle(tmp); + } + + @Override + public void fillOval(int x, int y, int width, int height) { + if (mP == null) { + mP = new Paint(); + } + Paint.Style tmp = mP.getStyle(); + mP.setStyle(Paint.Style.FILL); + mC.drawOval(new RectF(x, y, x + width, y + height), mP); + mP.setStyle(tmp); + } + + @Override + public void fillPolygon(int[] xpoints, int[] ypoints, int npoints) { + if (mP == null) { + mP = new Paint(); + } + Paint.Style tmp = mP.getStyle(); + mC.save(Canvas.CLIP_SAVE_FLAG); + + mP.setStyle(Paint.Style.FILL); + + GeneralPath filledPolygon = new GeneralPath( + GeneralPath.WIND_EVEN_ODD, npoints); + filledPolygon.moveTo(xpoints[0], ypoints[0]); + for (int index = 1; index < xpoints.length; index++) { + filledPolygon.lineTo(xpoints[index], ypoints[index]); + } + filledPolygon.closePath(); + Path path = getPath(filledPolygon); + mC.clipPath(path); + mC.drawPath(path, mP); + + mP.setStyle(tmp); + mC.restore(); + } + + @Override + public void fillRect(int x, int y, int width, int height) { + if (mP == null) { + mP = new Paint(); + } + Paint.Style tmp = mP.getStyle(); + mP.setStyle(Paint.Style.FILL); + mC.drawRect(new Rect(x, y, x + width, y + height), mP); + mP.setStyle(tmp); + } + + @Override + public void drawRect(int x, int y, int width, int height) { + int[] xpoints = { x, x, x + width, x + width }; + int[] ypoints = { y, y + height, y + height, y }; + drawPolygon(xpoints, ypoints, 4); + } + + @Override + public void fillRoundRect(int x, int y, int width, int height, + int arcWidth, int arcHeight) { + if (mP == null) { + mP = new Paint(); + } + mP.setStyle(Paint.Style.FILL); + mC.drawRoundRect(new RectF(x, y, x + width, y + height), arcWidth, + arcHeight, mP); + } + + @Override + public Shape getClip() { + return mCurrClip; + } + + @Override + public Rectangle getClipBounds() { + Rect r = mC.getClipBounds(); + return new Rectangle(r.left, r.top, r.width(), r.height()); + } + + @Override + public Color getColor() { + if (mP != null) { + return new Color(mP.getColor()); + } + return null; + } + + @Override + public Font getFont() { + return mFnt; + } + + @Override + public FontMetrics getFontMetrics(Font font) { + mFm = new FontMetricsImpl(font); + return mFm; + } + + @Override + public void setClip(int x, int y, int width, int height) { + int cl[] = {-1, x, y, -2, x, y + width, -2, x + height, y + width, -2, x + height, y}; + mCurrClip = new Area(createShape(cl)); + mC.clipRect(x, y, x + width, y + height, Region.Op.REPLACE); + + } + + @Override + public void setClip(Shape clip) { + mCurrClip = new Area(clip); + mC.clipPath(getPath(clip), Region.Op.REPLACE); + } + + @Override + public void setColor(Color c) { + if (mP == null) { + mP = new Paint(); + } + if (c == null) { + c = Color.decode("#00000000"); + } + mP.setColor(c.getRGB()); + } + + /** + * Font mapping: + * + * Family: + * + * Android AWT + * ------------------------------------- + * serif Serif / TimesRoman + * sans-serif SansSerif / Helvetica + * monospace Monospaced / Courier + * + * Style: + * + * Android AWT + * ------------------------------------- + * normal Plain + * bold bold + * italic italic + * + */ + @Override + public void setFont(Font font) { + if (font == null) { + return; + } + if (mP == null) { + mP = new Paint(); + } + + mFnt = font; + Typeface tf = null; + int sty = font.getStyle(); + String nam = font.getName(); + String aF = ""; + if (nam != null) { + if (nam.equalsIgnoreCase("Serif") + || nam.equalsIgnoreCase("TimesRoman")) { + aF = "serif"; + } else if (nam.equalsIgnoreCase("SansSerif") + || nam.equalsIgnoreCase("Helvetica")) { + aF = "sans-serif"; + } else if (nam.equalsIgnoreCase("Monospaced") + || nam.equalsIgnoreCase("Courier")) { + aF = "monospace"; + } + } + + switch (sty) { + case Font.PLAIN: + tf = Typeface.create(aF, Typeface.NORMAL); + break; + case Font.BOLD: + tf = Typeface.create(aF, Typeface.BOLD); + break; + case Font.ITALIC: + tf = Typeface.create(aF, Typeface.ITALIC); + break; + case Font.BOLD | Font.ITALIC: + tf = Typeface.create(aF, Typeface.BOLD_ITALIC); + break; + default: + tf = Typeface.DEFAULT; + } + + mP.setTextSize(font.getSize()); + mP.setTypeface(tf); + } + + @Override + public void drawBytes(byte[] data, int offset, int length, int x, int y) { + drawString(new String(data, offset, length), x, y); + } + + @Override + public void drawPolygon(Polygon p) { + drawPolygon(p.xpoints, p.ypoints, p.npoints); + } + + @Override + public void fillPolygon(Polygon p) { + fillPolygon(p.xpoints, p.ypoints, p.npoints); + } + + @Override + public Rectangle getClipBounds(Rectangle r) { + Shape clip = getClip(); + if (clip != null) { + Rectangle b = clip.getBounds(); + r.x = b.x; + r.y = b.y; + r.width = b.width; + r.height = b.height; + } + return r; + } + + @Override + public boolean hitClip(int x, int y, int width, int height) { + return getClipBounds().intersects(new Rectangle(x, y, width, height)); + } + + @Override + public void drawChars(char[] data, int offset, int length, int x, int y) { + mC.drawText(data, offset, length, x, y, mP); + } + + @Override + public void setPaintMode() { + if (mP == null) { + mP = new Paint(); + } + mP.setXfermode(null); + } + + @Override + public void setXORMode(Color color) { + if (mP == null) { + mP = new Paint(); + } + mP.setXfermode(new PixelXorXfermode(color.getRGB())); + } + + @Override + public void fill3DRect(int x, int y, int width, int height, boolean raised) { + Color color = getColor(); + Color colorUp, colorDown; + if (raised) { + colorUp = color.brighter(); + colorDown = color.darker(); + setColor(color); + } else { + colorUp = color.darker(); + colorDown = color.brighter(); + setColor(colorUp); + } + + width--; + height--; + fillRect(x+1, y+1, width-1, height-1); + + setColor(colorUp); + fillRect(x, y, width, 1); + fillRect(x, y+1, 1, height); + + setColor(colorDown); + fillRect(x+width, y, 1, height); + fillRect(x+1, y+height, width, 1); + } + + @Override + public void draw3DRect(int x, int y, int width, int height, boolean raised) { + Color color = getColor(); + Color colorUp, colorDown; + if (raised) { + colorUp = color.brighter(); + colorDown = color.darker(); + } else { + colorUp = color.darker(); + colorDown = color.brighter(); + } + + setColor(colorUp); + fillRect(x, y, width, 1); + fillRect(x, y+1, 1, height); + + setColor(colorDown); + fillRect(x+width, y, 1, height); + fillRect(x+1, y+height, width, 1); + } + + public void copyArea(Canvas canvas, int sx, int sy, int width, int height, int dx, int dy) { + sx += getTransform().getTranslateX(); + sy += getTransform().getTranslateY(); + + // NativeUtils.nativeScrollRect(canvas, new Rect(sx, sy, sx + width, sy + height), dx, dy); + } +} diff --git a/app/src/main/java/com/android/internal/awt/AndroidGraphicsConfiguration.java b/app/src/main/java/com/android/internal/awt/AndroidGraphicsConfiguration.java new file mode 100644 index 000000000..0c888cd2d --- /dev/null +++ b/app/src/main/java/com/android/internal/awt/AndroidGraphicsConfiguration.java @@ -0,0 +1,96 @@ +/* + * Copyright 2007, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.awt; + +import com.android.internal.awt.AndroidGraphics2D; + +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.Rectangle; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.VolatileImage; + +import android.graphics.Canvas; + +public class AndroidGraphicsConfiguration extends GraphicsConfiguration { + + @Override + public BufferedImage createCompatibleImage(int width, int height) { + // TODO Auto-generated method stub + return null; + } + + @Override + public BufferedImage createCompatibleImage(int width, int height, + int transparency) { + // TODO Auto-generated method stub + return null; + } + + @Override + public VolatileImage createCompatibleVolatileImage(int width, int height) { + // TODO Auto-generated method stub + return null; + } + + @Override + public VolatileImage createCompatibleVolatileImage(int width, int height, + int transparency) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Rectangle getBounds() { + Canvas c = AndroidGraphics2D.getAndroidCanvas(); + if(c != null) + return new Rectangle(0, 0, c.getWidth(), c.getHeight()); + return null; + } + + @Override + public ColorModel getColorModel() { + // TODO Auto-generated method stub + return null; + } + + @Override + public ColorModel getColorModel(int transparency) { + // TODO Auto-generated method stub + return null; + } + + @Override + public AffineTransform getDefaultTransform() { + return new AffineTransform(); + } + + @Override + public GraphicsDevice getDevice() { + // TODO Auto-generated method stub + return null; + } + + @Override + public AffineTransform getNormalizingTransform() { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/app/src/main/java/com/android/internal/awt/AndroidGraphicsFactory.java b/app/src/main/java/com/android/internal/awt/AndroidGraphicsFactory.java new file mode 100644 index 000000000..ca255b559 --- /dev/null +++ b/app/src/main/java/com/android/internal/awt/AndroidGraphicsFactory.java @@ -0,0 +1,87 @@ +/* + * Copyright 2007, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.awt; + +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.GraphicsEnvironment; +import java.awt.peer.FontPeer; + +import org.apache.harmony.awt.gl.MultiRectArea; +import org.apache.harmony.awt.gl.font.AndroidFont; +import org.apache.harmony.awt.gl.font.FontManager; +import org.apache.harmony.awt.gl.font.FontMetricsImpl; +import org.apache.harmony.awt.gl.font.AndroidFontManager; +import org.apache.harmony.awt.wtk.NativeWindow; +import org.apache.harmony.awt.wtk.WindowFactory; +import org.apache.harmony.awt.gl.CommonGraphics2DFactory; + +import android.graphics.Canvas; +import android.graphics.Paint; +import android.content.Context; + +public class AndroidGraphicsFactory extends CommonGraphics2DFactory { + + public GraphicsEnvironment createGraphicsEnvironment(WindowFactory wf) { + // TODO Auto-generated method stub + return null; + } + + public Font embedFont(String fontFilePath) { + // TODO Auto-generated method stub + return null; + } + + public FontManager getFontManager() { + return AndroidFontManager.inst; + } + + public FontMetrics getFontMetrics(Font font) { + return new FontMetricsImpl(font); + } + + public FontPeer getFontPeer(Font font) { + //return getFontManager().getFontPeer(font.getName(), font.getStyle(), font.getSize()); + return new AndroidFont(font.getName(), font.getStyle(), font.getSize()); + } + + public Graphics2D getGraphics2D(NativeWindow win, int translateX, + int translateY, MultiRectArea clip) { + // TODO Auto-generated method stub + return null; + } + + public Graphics2D getGraphics2D(NativeWindow win, int translateX, + int translateY, int width, int height) { + // TODO Auto-generated method stub + return null; + } + + public Graphics2D getGraphics2D(Context ctx, Canvas c, Paint p) { + return AndroidGraphics2D.getInstance(ctx, c, p); + } + + public Graphics2D getGraphics2D(Canvas c, Paint p) { + throw new RuntimeException("Not supported!"); + } + + public Graphics2D getGraphics2D() { + return AndroidGraphics2D.getInstance(); + } + +} diff --git a/app/src/main/java/com/android/internal/awt/AndroidImageDecoder.java b/app/src/main/java/com/android/internal/awt/AndroidImageDecoder.java new file mode 100644 index 000000000..81b2e1a8c --- /dev/null +++ b/app/src/main/java/com/android/internal/awt/AndroidImageDecoder.java @@ -0,0 +1,274 @@ +/* + * Copyright 2007, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.awt; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; + +import java.awt.Transparency; +import java.awt.color.ColorSpace; +//import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.ComponentColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.DirectColorModel; +import java.awt.image.ImageConsumer; +import java.awt.image.IndexColorModel; +import java.io.IOException; +import java.io.InputStream; +import java.util.Hashtable; + +import org.apache.harmony.awt.gl.image.DecodingImageSource; +import org.apache.harmony.awt.gl.image.ImageDecoder; +import org.apache.harmony.awt.internal.nls.Messages; + +public class AndroidImageDecoder extends ImageDecoder { + + private static final int hintflags = + ImageConsumer.SINGLEFRAME | // PNG is a static image + ImageConsumer.TOPDOWNLEFTRIGHT | // This order is only one possible + ImageConsumer.COMPLETESCANLINES; // Don't deliver incomplete scanlines + + // Each pixel is a grayscale sample. + private static final int PNG_COLOR_TYPE_GRAY = 0; + // Each pixel is an R,G,B triple. + private static final int PNG_COLOR_TYPE_RGB = 2; + // Each pixel is a palette index, a PLTE chunk must appear. + private static final int PNG_COLOR_TYPE_PLTE = 3; + // Each pixel is a grayscale sample, followed by an alpha sample. + private static final int PNG_COLOR_TYPE_GRAY_ALPHA = 4; + // Each pixel is an R,G,B triple, followed by an alpha sample. + private static final int PNG_COLOR_TYPE_RGBA = 6; + + private static final int NB_OF_LINES_PER_CHUNK = 1; // 0 = full image + + Bitmap bm; // The image as decoded by Android + + // Header information + int imageWidth; // Image size + int imageHeight; + int colorType; // One of the PNG_ constants from above + int bitDepth; // Number of bits per color + byte cmap[]; // The color palette for index color models + ColorModel model; // The corresponding AWT color model + + boolean transferInts; // Is transfer of type int or byte? + int dataElementsPerPixel; + + // Buffers for decoded image data + byte byteOut[]; + int intOut[]; + + + public AndroidImageDecoder(DecodingImageSource src, InputStream is) { + super(src, is); + dataElementsPerPixel = 1; + } + + @Override + /** + * All the decoding is done in Android + * + * AWT???: Method returns only once the image is completly + * decoded; decoding is not done asynchronously + */ + public void decodeImage() throws IOException { + try { + bm = BitmapFactory.decodeStream(inputStream); + if (bm == null) { + throw new IOException("Input stream empty and no image cached"); + } + + // Check size + imageWidth = bm.getWidth(); + imageHeight = bm.getHeight(); + if (imageWidth < 0 || imageHeight < 0 ) { + throw new RuntimeException("Illegal image size: " + + imageWidth + ", " + imageHeight); + } + + // We got the image fully decoded; now send all image data to AWT + setDimensions(imageWidth, imageHeight); + model = createColorModel(); + setColorModel(model); + setHints(hintflags); + setProperties(new Hashtable()); // Empty + sendPixels(NB_OF_LINES_PER_CHUNK != 0 ? NB_OF_LINES_PER_CHUNK : imageHeight); + imageComplete(ImageConsumer.STATICIMAGEDONE); + } catch (IOException e) { + throw e; + } catch (RuntimeException e) { + imageComplete(ImageConsumer.IMAGEERROR); + throw e; + } finally { + closeStream(); + } + } + + /** + * Create the AWT color model + * + * ???AWT: Android Bitmaps are always of type: ARGB-8888-Direct color model + * + * However, we leave the code here for a more powerfull decoder + * that returns a native model, and the conversion is then handled + * in AWT. With such a decoder, we would need to get the colorType, + * the bitDepth, (and the color palette for an index color model) + * from the image and construct the correct color model here. + */ + private ColorModel createColorModel() { + ColorModel cm = null; + int bmModel = 5; // TODO This doesn't exist: bm.getColorModel(); + cmap = null; + + switch (bmModel) { + // A1_MODEL + case 1: + colorType = PNG_COLOR_TYPE_GRAY; + bitDepth = 1; + break; + + // A8_MODEL + case 2: + colorType = PNG_COLOR_TYPE_GRAY_ALPHA; + bitDepth = 8; + break; + + // INDEX8_MODEL + // RGB_565_MODEL + // ARGB_8888_MODEL + case 3: + case 4: + case 5: + colorType = bm.hasAlpha() ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB; + bitDepth = 8; + break; + + default: + // awt.3C=Unknown PNG color type + throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$ + } + + switch (colorType) { + + case PNG_COLOR_TYPE_GRAY: { + if (bitDepth != 8 && bitDepth != 4 && bitDepth != 2 && bitDepth != 1) { + // awt.3C=Unknown PNG color type + throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$ + } + + // Create gray color model + int numEntries = 1 << bitDepth; + int scaleFactor = 255 / (numEntries-1); + byte comps[] = new byte[numEntries]; + for (int i = 0; i < numEntries; i++) { + comps[i] = (byte) (i * scaleFactor); + } + cm = new IndexColorModel(bitDepth, numEntries, comps, comps, comps); + + transferInts = false; + break; + } + + case PNG_COLOR_TYPE_RGB: { + if (bitDepth != 8) { + // awt.3C=Unknown PNG color type + throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$ + } + + cm = new DirectColorModel(24, 0xff0000, 0xFF00, 0xFF); + + transferInts = true; + break; + } + + case PNG_COLOR_TYPE_PLTE: { + if (bitDepth != 8 && bitDepth != 4 && bitDepth != 2 && bitDepth != 1) { + // awt.3C=Unknown PNG color type + throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$ + } + + if (cmap == null) { + throw new IllegalStateException("Palette color type is not supported"); + } + + cm = new IndexColorModel(bitDepth, cmap.length / 3, cmap, 0, false); + + transferInts = false; + break; + } + + case PNG_COLOR_TYPE_GRAY_ALPHA: { + if (bitDepth != 8) { + // awt.3C=Unknown PNG color type + throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$ + } + + cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY), + true, false, + Transparency.TRANSLUCENT, + DataBuffer.TYPE_BYTE); + + transferInts = false; + dataElementsPerPixel = 2; + break; + } + + case PNG_COLOR_TYPE_RGBA: { + if (bitDepth != 8) { + // awt.3C=Unknown PNG color type + throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$ + } + + cm = ColorModel.getRGBdefault(); + + transferInts = true; + break; + } + default: + // awt.3C=Unknown PNG color type + throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$ + } + + return cm; + } + + private void sendPixels(int nbOfLinesPerChunk) { + int w = imageWidth; + int h = imageHeight; + int n = 1; + if (nbOfLinesPerChunk > 0 && nbOfLinesPerChunk <= h) { + n = nbOfLinesPerChunk; + } + + if (transferInts) { + // Create output buffer + intOut = new int[w * n]; + for (int yi = 0; yi < h; yi += n) { + // Last chunk might contain less liness + if (n > 1 && h - yi < n ) { + n = h - yi; + } + bm.getPixels(intOut, 0, w, 0, yi, w, n); + setPixels(0, yi, w, n, model, intOut, 0, w); + } + } else { + // Android bitmaps always store ints (ARGB-8888 direct model) + throw new RuntimeException("Byte transfer not supported"); + } + } + +} diff --git a/app/src/main/java/com/android/internal/awt/AndroidJavaBlitter.java b/app/src/main/java/com/android/internal/awt/AndroidJavaBlitter.java new file mode 100644 index 000000000..423b534cb --- /dev/null +++ b/app/src/main/java/com/android/internal/awt/AndroidJavaBlitter.java @@ -0,0 +1,536 @@ +/* + * Copyright 2007, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.awt; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; +import org.apache.harmony.awt.gl.MultiRectArea; +import org.apache.harmony.awt.gl.Surface; +import org.apache.harmony.awt.gl.XORComposite; +import org.apache.harmony.awt.gl.render.Blitter; + +import java.awt.*; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.image.ColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferInt; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; + +public class AndroidJavaBlitter implements Blitter { + + private Canvas canvas; + private Paint paint; + private int colorCache; + + public AndroidJavaBlitter(Canvas c) { + this.canvas = c; + this.paint = new Paint(); + this.paint.setStrokeWidth(1); + } + + /** + * Instead of multiplication and division we are using values from + * Lookup tables. + */ + static byte mulLUT[][]; // Lookup table for multiplication + static byte divLUT[][]; // Lookup table for division + + static{ + mulLUT = new byte[256][256]; + for(int i = 0; i < 256; i++){ + for(int j = 0; j < 256; j++){ + mulLUT[i][j] = (byte)((float)(i * j)/255 + 0.5f); + } + } + divLUT = new byte[256][256]; + for(int i = 1; i < 256; i++){ + for(int j = 0; j < i; j++){ + divLUT[i][j] = (byte)(((float)j / 255) / ((float)i/ 255) * 255 + 0.5f); + } + for(int j = i; j < 256; j++){ + divLUT[i][j] = (byte)255; + } + } + } + + final static int AlphaCompositeMode = 1; + final static int XORMode = 2; + + public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY, + Surface dstSurf, int width, int height, AffineTransform sysxform, + AffineTransform xform, Composite comp, Color bgcolor, + MultiRectArea clip) { + + if(xform == null){ + blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, width, height, + sysxform, comp, bgcolor, clip); + }else{ + double scaleX = xform.getScaleX(); + double scaleY = xform.getScaleY(); + double scaledX = dstX / scaleX; + double scaledY = dstY / scaleY; + AffineTransform at = new AffineTransform(); + at.setToTranslation(scaledX, scaledY); + xform.concatenate(at); + sysxform.concatenate(xform); + blit(srcX, srcY, srcSurf, 0, 0, dstSurf, width, height, + sysxform, comp, bgcolor, clip); + } + + } + + public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY, + Surface dstSurf, int width, int height, AffineTransform sysxform, + Composite comp, Color bgcolor, MultiRectArea clip) { + + if(sysxform == null) { + sysxform = new AffineTransform(); + } + int type = sysxform.getType(); + switch(type){ + case AffineTransform.TYPE_TRANSLATION: + dstX += sysxform.getTranslateX(); + dstY += sysxform.getTranslateY(); + case AffineTransform.TYPE_IDENTITY: + simpleBlit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, + width, height, comp, bgcolor, clip); + break; + default: + int srcW = srcSurf.getWidth(); + int srcH = srcSurf.getHeight(); + + int w = srcX + width < srcW ? width : srcW - srcX; + int h = srcY + height < srcH ? height : srcH - srcY; + + ColorModel srcCM = srcSurf.getColorModel(); + Raster srcR = srcSurf.getRaster().createChild(srcX, srcY, + w, h, 0, 0, null); + + ColorModel dstCM = dstSurf.getColorModel(); + WritableRaster dstR = dstSurf.getRaster(); + + transformedBlit(srcCM, srcR, 0, 0, dstCM, dstR, dstX, dstY, w, h, + sysxform, comp, bgcolor, clip); + + } + } + + public void simpleBlit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY, + Surface dstSurf, int width, int height, Composite comp, + Color bgcolor, MultiRectArea clip) { + + // TODO It's possible, though unlikely that we might encounter non-int[] + // data buffers. In this case the following code needs to have several + // branches that take this into account. + data = (DataBufferInt)srcSurf.getRaster().getDataBuffer(); + int[] pixels = data.getData(); + if (!srcSurf.getColorModel().hasAlpha()) { + // This wouldn't be necessary if Android supported RGB_888. + for (int i = 0; i < pixels.length; i++) { + pixels[i] = pixels[i] | 0xff000000; + } + } + bmap = Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888); + canvas.drawBitmap(bmap, dstX, dstY, paint); + } + + public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY, + Surface dstSurf, int width, int height, Composite comp, + Color bgcolor, MultiRectArea clip) { + + javaBlt(srcX, srcY, srcSurf.getWidth(), srcSurf.getHeight(), + srcSurf.getColorModel(), srcSurf.getRaster(), dstX, dstY, + dstSurf.getWidth(), dstSurf.getHeight(), + dstSurf.getColorModel(), dstSurf.getRaster(), + width, height, comp, bgcolor, clip); + + } + + public void javaBlt(int srcX, int srcY, int srcW, int srcH, + ColorModel srcCM, Raster srcRast, int dstX, int dstY, + int dstW, int dstH, ColorModel dstCM, WritableRaster dstRast, + int width, int height, Composite comp, Color bgcolor, + MultiRectArea clip){ + + int srcX2 = srcW - 1; + int srcY2 = srcH - 1; + int dstX2 = dstW - 1; + int dstY2 = dstH - 1; + + if(srcX < 0){ + width += srcX; + srcX = 0; + } + if(srcY < 0){ + height += srcY; + srcY = 0; + } + + if(dstX < 0){ + width += dstX; + srcX -= dstX; + dstX = 0; + } + if(dstY < 0){ + height += dstY; + srcY -= dstY; + dstY = 0; + } + + if(srcX > srcX2 || srcY > srcY2) { + return; + } + if(dstX > dstX2 || dstY > dstY2) { + return; + } + + if(srcX + width > srcX2) { + width = srcX2 - srcX + 1; + } + if(srcY + height > srcY2) { + height = srcY2 - srcY + 1; + } + if(dstX + width > dstX2) { + width = dstX2 - dstX + 1; + } + if(dstY + height > dstY2) { + height = dstY2 - dstY + 1; + } + + if(width <= 0 || height <= 0) { + return; + } + + int clipRects[]; + if(clip != null) { + clipRects = clip.rect; + } else { + clipRects = new int[]{5, 0, 0, dstW - 1, dstH - 1}; + } + + boolean isAlphaComp = false; + int rule = 0; + float alpha = 0; + boolean isXORComp = false; + Color xorcolor = null; + CompositeContext cont = null; + + if(comp instanceof AlphaComposite){ + isAlphaComp = true; + AlphaComposite ac = (AlphaComposite) comp; + rule = ac.getRule(); + alpha = ac.getAlpha(); + }else if(comp instanceof XORComposite){ + isXORComp = true; + XORComposite xcomp = (XORComposite) comp; + xorcolor = xcomp.getXORColor(); + }else{ + cont = comp.createContext(srcCM, dstCM, null); + } + + for(int i = 1; i < clipRects[0]; i += 4){ + int _sx = srcX; + int _sy = srcY; + + int _dx = dstX; + int _dy = dstY; + + int _w = width; + int _h = height; + + int cx = clipRects[i]; // Clipping left top X + int cy = clipRects[i + 1]; // Clipping left top Y + int cx2 = clipRects[i + 2]; // Clipping right bottom X + int cy2 = clipRects[i + 3]; // Clipping right bottom Y + + if(_dx > cx2 || _dy > cy2 || dstX2 < cx || dstY2 < cy) { + continue; + } + + if(cx > _dx){ + int shx = cx - _dx; + _w -= shx; + _dx = cx; + _sx += shx; + } + + if(cy > _dy){ + int shy = cy - _dy; + _h -= shy; + _dy = cy; + _sy += shy; + } + + if(_dx + _w > cx2 + 1){ + _w = cx2 - _dx + 1; + } + + if(_dy + _h > cy2 + 1){ + _h = cy2 - _dy + 1; + } + + if(_sx > srcX2 || _sy > srcY2) { + continue; + } + + if(isAlphaComp){ + alphaCompose(_sx, _sy, srcCM, srcRast, _dx, _dy, + dstCM, dstRast, _w, _h, rule, alpha, bgcolor); + }else if(isXORComp){ + xorCompose(_sx, _sy, srcCM, srcRast, _dx, _dy, + dstCM, dstRast, _w, _h, xorcolor); + }else{ + Raster sr = srcRast.createChild(_sx, _sy, _w, _h, 0, 0, null); + WritableRaster dr = dstRast.createWritableChild(_dx, _dy, + _w, _h, 0, 0, null); + cont.compose(sr, dr, dr); + } + } + + } + + DataBufferInt data; + Bitmap bmap, bmp; + + void alphaCompose(int srcX, int srcY, ColorModel srcCM, Raster srcRast, + int dstX, int dstY, ColorModel dstCM, WritableRaster dstRast, + int width, int height, int rule, float alpha, Color bgcolor){ + + Object srcPixel = getTransferArray(srcRast, 1); + data = (DataBufferInt)srcRast.getDataBuffer(); + int pix[] = data.getData(); + bmap = Bitmap.createBitmap(pix, width, height, Bitmap.Config.RGB_565); + canvas.drawBitmap(bmap, dstX, dstY, paint); + } + + void render(int[] img, int x, int y, int width, int height) { + canvas.drawBitmap(Bitmap.createBitmap(img, width, height, Bitmap.Config.ARGB_8888), x, y, paint); + } + + void xorCompose(int srcX, int srcY, ColorModel srcCM, Raster srcRast, + int dstX, int dstY, ColorModel dstCM, WritableRaster dstRast, + int width, int height, Color xorcolor){ + + data = (DataBufferInt)srcRast.getDataBuffer(); + int pix[] = data.getData(); + bmap = Bitmap.createBitmap(pix, width, height, Bitmap.Config.RGB_565); + canvas.drawBitmap(bmap, dstX, dstY, paint); + } + + private void transformedBlit(ColorModel srcCM, Raster srcR, int srcX, int srcY, + ColorModel dstCM, WritableRaster dstR, int dstX, int dstY, + int width, int height, AffineTransform at, Composite comp, + Color bgcolor, MultiRectArea clip) { + + data = (DataBufferInt)srcR.getDataBuffer(); + int[] pixels = data.getData(); + if (!srcCM.hasAlpha()) { + // This wouldn't be necessary if Android supported RGB_888. + for (int i = 0; i < pixels.length; i++) { + pixels[i] = pixels[i] | 0xff000000; + } + } + bmap = Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888); + + Matrix tm = new Matrix(); + tm.setConcat(canvas.getMatrix(), AndroidGraphics2D.createMatrixObj(at)); + if(at.getType() > 1) { + bmp = Bitmap.createBitmap(bmap, 0, 0, width, height, tm, true); + } else { + bmp = Bitmap.createBitmap(bmap, 0, 0, width, height, tm, false); + } + canvas.drawBitmap(bmp, dstX + (float)at.getTranslateX(), dstY + (float)at.getTranslateY(), paint); + } + + private Rectangle2D getBounds2D(AffineTransform at, Rectangle r) { + int x = r.x; + int y = r.y; + int width = r.width; + int height = r.height; + + float[] corners = { + x, y, + x + width, y, + x + width, y + height, + x, y + height + }; + + at.transform(corners, 0, corners, 0, 4); + + Rectangle2D.Float bounds = new Rectangle2D.Float(corners[0], corners[1], 0 , 0); + bounds.add(corners[2], corners[3]); + bounds.add(corners[4], corners[5]); + bounds.add(corners[6], corners[7]); + + return bounds; + } + + private int compose(int srcRGB, boolean isSrcAlphaPre, + int dstRGB, boolean dstHasAlpha, boolean isDstAlphaPre, + int rule, int srcConstAlpha){ + + int sa, sr, sg, sb, da, dr, dg, db; + + sa = (srcRGB >> 24) & 0xff; + sr = (srcRGB >> 16) & 0xff; + sg = (srcRGB >> 8) & 0xff; + sb = srcRGB & 0xff; + + if(isSrcAlphaPre){ + sa = mulLUT[srcConstAlpha][sa] & 0xff; + sr = mulLUT[srcConstAlpha][sr] & 0xff; + sg = mulLUT[srcConstAlpha][sg] & 0xff; + sb = mulLUT[srcConstAlpha][sb] & 0xff; + }else{ + sa = mulLUT[srcConstAlpha][sa] & 0xff; + sr = mulLUT[sa][sr] & 0xff; + sg = mulLUT[sa][sg] & 0xff; + sb = mulLUT[sa][sb] & 0xff; + } + + da = (dstRGB >> 24) & 0xff; + dr = (dstRGB >> 16) & 0xff; + dg = (dstRGB >> 8) & 0xff; + db = dstRGB & 0xff; + + if(!isDstAlphaPre){ + dr = mulLUT[da][dr] & 0xff; + dg = mulLUT[da][dg] & 0xff; + db = mulLUT[da][db] & 0xff; + } + + int Fs = 0; + int Fd = 0; + switch(rule){ + case AlphaComposite.CLEAR: + break; + + case AlphaComposite.DST: + Fd = 255; + break; + + case AlphaComposite.DST_ATOP: + Fs = 255 - da; + Fd = sa; + break; + + case AlphaComposite.DST_IN: + Fd = sa; + break; + + case AlphaComposite.DST_OUT: + Fd = 255 - sa; + break; + + case AlphaComposite.DST_OVER: + Fs = 255 - da; + Fd = 255; + break; + + case AlphaComposite.SRC: + Fs = 255; + break; + + case AlphaComposite.SRC_ATOP: + Fs = da; + Fd = 255 - sa; + break; + + case AlphaComposite.SRC_IN: + Fs = da; + break; + + case AlphaComposite.SRC_OUT: + Fs = 255 - da; + break; + + case AlphaComposite.SRC_OVER: + Fs = 255; + Fd = 255 - sa; + break; + + case AlphaComposite.XOR: + Fs = 255 - da; + Fd = 255 - sa; + break; + } + dr = (mulLUT[sr][Fs] & 0xff) + (mulLUT[dr][Fd] & 0xff); + dg = (mulLUT[sg][Fs] & 0xff) + (mulLUT[dg][Fd] & 0xff); + db = (mulLUT[sb][Fs] & 0xff) + (mulLUT[db][Fd] & 0xff); + + da = (mulLUT[sa][Fs] & 0xff) + (mulLUT[da][Fd] & 0xff); + + if(!isDstAlphaPre){ + if(da != 255){ + dr = divLUT[da][dr] & 0xff; + dg = divLUT[da][dg] & 0xff; + db = divLUT[da][db] & 0xff; + } + } + if(!dstHasAlpha) { + da = 0xff; + } + dstRGB = (da << 24) | (dr << 16) | (dg << 8) | db; + + return dstRGB; + + } + + /** + * Allocate an array that can be use to store the result for a + * Raster.getDataElements call. + * @param raster Raster (type) where the getDataElements call will be made. + * @param nbPixels How many pixels to store in the array at most + * @return the result array or null + */ + private Object getTransferArray(Raster raster, int nbPixels) { + int transferType = raster.getTransferType(); + int nbDataElements = raster.getSampleModel().getNumDataElements(); + int n = nbDataElements * nbPixels; + switch (transferType) { + case DataBuffer.TYPE_BYTE: + return new byte[n]; + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: + return new short[n]; + case DataBuffer.TYPE_INT: + return new int[n]; + case DataBuffer.TYPE_FLOAT: + return new float[n]; + case DataBuffer.TYPE_DOUBLE: + return new double[n]; + case DataBuffer.TYPE_UNDEFINED: + default: + return null; + } + } + + /** + * Draw a pixel + */ + private void dot(int x, int y, int clr) { + if (colorCache != clr) { + paint.setColor(clr); + colorCache = clr; + } + canvas.drawLine(x, y, x + 1, y + 1, paint); + } +} diff --git a/app/src/main/java/com/android/internal/awt/AndroidNativeEventQueue.java b/app/src/main/java/com/android/internal/awt/AndroidNativeEventQueue.java new file mode 100644 index 000000000..fc3061457 --- /dev/null +++ b/app/src/main/java/com/android/internal/awt/AndroidNativeEventQueue.java @@ -0,0 +1,75 @@ +/* + * Copyright 2007, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.awt; + +import org.apache.harmony.awt.wtk.NativeEventQueue; + +public class AndroidNativeEventQueue extends NativeEventQueue { + + private Object eventMonitor; + + public AndroidNativeEventQueue() { + super(); + eventMonitor = getEventMonitor(); + } + + @Override + public void awake() { + synchronized (eventMonitor) { + eventMonitor.notify(); + } + } + + @Override + public void dispatchEvent() { + //???AWT + System.out.println(getClass()+": empty method called"); + } + + @Override + public long getJavaWindow() { + //???AWT + System.out.println(getClass()+": empty method called"); + return 0; + } + + @Override + public void performLater(Task task) { + //???AWT + System.out.println(getClass()+": empty method called"); + } + + @Override + public void performTask(Task task) { + //???AWT + System.out.println(getClass()+": empty method called"); + } + + @Override + public boolean waitEvent() { + while (isEmpty() ) { + synchronized (eventMonitor) { + try { + eventMonitor.wait(1000); + } catch (InterruptedException ignore) { + } + } + } + return false; + } + +} diff --git a/app/src/main/java/com/android/internal/awt/AndroidWTK.java b/app/src/main/java/com/android/internal/awt/AndroidWTK.java new file mode 100644 index 000000000..1609d119e --- /dev/null +++ b/app/src/main/java/com/android/internal/awt/AndroidWTK.java @@ -0,0 +1,88 @@ +/* + * Copyright 2007, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.awt; + +import java.awt.GraphicsDevice; + +import org.apache.harmony.awt.wtk.CursorFactory; +import org.apache.harmony.awt.wtk.GraphicsFactory; +import org.apache.harmony.awt.wtk.NativeEventQueue; +import org.apache.harmony.awt.wtk.NativeIM; +import org.apache.harmony.awt.wtk.NativeMouseInfo; +import org.apache.harmony.awt.wtk.NativeRobot; +import org.apache.harmony.awt.wtk.SystemProperties; +import org.apache.harmony.awt.wtk.WTK; +import org.apache.harmony.awt.wtk.WindowFactory; + +public class AndroidWTK extends WTK { + + private AndroidGraphicsFactory mAgf; + private AndroidNativeEventQueue mAneq; + + @Override + public CursorFactory getCursorFactory() { + // TODO Auto-generated method stub + return null; + } + + @Override + public GraphicsFactory getGraphicsFactory() { + if(mAgf == null) { + mAgf = new AndroidGraphicsFactory(); + } + return mAgf; + } + + @Override + public NativeEventQueue getNativeEventQueue() { + if(mAneq == null) { + mAneq = new AndroidNativeEventQueue(); + } + return mAneq; + } + + @Override + public NativeIM getNativeIM() { + // TODO Auto-generated method stub + return null; + } + + @Override + public NativeMouseInfo getNativeMouseInfo() { + // TODO Auto-generated method stub + return null; + } + + @Override + public NativeRobot getNativeRobot(GraphicsDevice screen) { + // TODO Auto-generated method stub + return null; + } + + @Override + public SystemProperties getSystemProperties() { + // TODO Auto-generated method stub + return null; + } + + @Override + public WindowFactory getWindowFactory() { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/app/src/main/java/com/android/internal/awt/AwtFactory.java b/app/src/main/java/com/android/internal/awt/AwtFactory.java new file mode 100644 index 000000000..6e667b234 --- /dev/null +++ b/app/src/main/java/com/android/internal/awt/AwtFactory.java @@ -0,0 +1,52 @@ +/* + * Copyright 2007, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.awt; + +import java.awt.Graphics2D; +import java.awt.Toolkit; + +import org.apache.harmony.awt.wtk.GraphicsFactory; + +import android.graphics.Canvas; +import android.graphics.Paint; + +public class AwtFactory { + + private static GraphicsFactory gf; + + /** + * Use this method to get acces to AWT drawing primitives and to + * render into the surface area of a Android widget. Origin and + * clip of the returned graphics object are the same as in the + * corresponding Android widget. + * + * @param c Canvas of the android widget to draw into + * @param p The default drawing parameters such as font, + * stroke, foreground and background colors, etc. + * @return The AWT Graphics object that makes all AWT + * drawing primitives available in the androind world. + */ + public static Graphics2D getAwtGraphics(Canvas c, Paint p) { + // AWT?? TODO: test it! + if (null == gf) { + Toolkit tk = Toolkit.getDefaultToolkit(); + gf = tk.getGraphicsFactory(); + } + return gf.getGraphics2D(c, p); + } + +} diff --git a/app/src/main/java/com/android/internal/awt/ImageOutputStreamWrapper.java b/app/src/main/java/com/android/internal/awt/ImageOutputStreamWrapper.java new file mode 100644 index 000000000..92185fde3 --- /dev/null +++ b/app/src/main/java/com/android/internal/awt/ImageOutputStreamWrapper.java @@ -0,0 +1,66 @@ +/* + * Copyright 2007, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.awt; + +import java.io.IOException; +import java.io.OutputStream; + +import javax.imageio.stream.ImageOutputStream; + +public class ImageOutputStreamWrapper extends OutputStream { + + protected ImageOutputStream mIos; + + private byte[] mBuff; + + public ImageOutputStreamWrapper(ImageOutputStream ios) { + if (null == ios) { + throw new IllegalArgumentException("ImageOutputStream must not be null"); + } + this.mIos = ios; + this.mBuff = new byte[1]; + } + + public ImageOutputStream getImageOutputStream() { + return mIos; + } + + @Override + public void write(int oneByte) throws IOException { + mBuff[0] = (byte)oneByte; + mIos.write(mBuff, 0, 1); + } + + public void write(byte[] b) throws IOException { + mIos.write(b, 0, b.length); + } + + public void write(byte[] b, int off, int len) throws IOException { + mIos.write(b, off, len); + } + + public void flush() throws IOException { + mIos.flush(); + } + + public void close() throws IOException { + if (mIos == null) { + throw new IOException("Stream already closed"); + } + mIos = null; + } +} diff --git a/app/src/main/java/com/android/internal/awt/NullGraphics2D.java b/app/src/main/java/com/android/internal/awt/NullGraphics2D.java new file mode 100644 index 000000000..b181c1eec --- /dev/null +++ b/app/src/main/java/com/android/internal/awt/NullGraphics2D.java @@ -0,0 +1,456 @@ +package com.android.internal.awt; + +import java.awt.*; +import java.text.*; +import java.awt.image.renderable.*; +import java.awt.font.*; +import java.awt.image.*; +import java.awt.RenderingHints.*; +import java.util.*; +import java.awt.geom.*; + +public class NullGraphics2D extends Graphics2D +{ + + @Override + public void clearRect(int x, int y, int width, int height) + { + // TODO: Implement this method + } + + @Override + public void clipRect(int x, int y, int width, int height) + { + // TODO: Implement this method + } + + @Override + public void copyArea(int sx, int sy, int width, int height, int dx, int dy) + { + // TODO: Implement this method + } + + @Override + public Graphics create() + { + return this; + } + + @Override + public void dispose() + { + // TODO: Implement this method + } + + @Override + public void drawArc(int x, int y, int width, int height, int sa, int ea) + { + // TODO: Implement this method + } + + @Override + public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) + { + // TODO: Implement this method + return false; + } + + @Override + public boolean drawImage(Image img, int x, int y, ImageObserver observer) + { + // TODO: Implement this method + return false; + } + + @Override + public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer) + { + // TODO: Implement this method + return false; + } + + @Override + public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) + { + // TODO: Implement this method + return false; + } + + @Override + public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor, ImageObserver observer) + { + // TODO: Implement this method + return false; + } + + @Override + public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer) + { + // TODO: Implement this method + return false; + } + + @Override + public void drawLine(int x1, int y1, int x2, int y2) + { + // TODO: Implement this method + } + + @Override + public void drawOval(int x, int y, int width, int height) + { + // TODO: Implement this method + } + + @Override + public void drawPolygon(int[] xpoints, int[] ypoints, int npoints) + { + // TODO: Implement this method + } + + @Override + public void drawPolyline(int[] xpoints, int[] ypoints, int npoints) + { + // TODO: Implement this method + } + + @Override + public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) + { + // TODO: Implement this method + } + + @Override + public void fillArc(int x, int y, int width, int height, int sa, int ea) + { + // TODO: Implement this method + } + + @Override + public void fillOval(int x, int y, int width, int height) + { + // TODO: Implement this method + } + + @Override + public void fillPolygon(int[] xpoints, int[] ypoints, int npoints) + { + // TODO: Implement this method + } + + @Override + public void fillRect(int x, int y, int width, int height) + { + // TODO: Implement this method + } + + @Override + public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) + { + // TODO: Implement this method + } + + @Override + public Shape getClip() + { + // TODO: Implement this method + return null; + } + + @Override + public Rectangle getClipBounds() + { + // TODO: Implement this method + return null; + } + + @Override + public Color getColor() + { + return Color.BLACK; + } + + @Override + public Font getFont() + { + // TODO: Implement this method + return Font.decode(null); + } + + @Override + public FontMetrics getFontMetrics(Font font) + { + // TODO: Implement this method + return new FontMetrics(getFont()){}; + } + + @Override + public void setClip(int x, int y, int width, int height) + { + // TODO: Implement this method + } + + @Override + public void setClip(Shape clip) + { + // TODO: Implement this method + } + + @Override + public void setColor(Color c) + { + // TODO: Implement this method + } + + @Override + public void setFont(Font font) + { + // TODO: Implement this method + } + + @Override + public void setPaintMode() + { + // TODO: Implement this method + } + + @Override + public void setXORMode(Color color) + { + // TODO: Implement this method + } + + @Override + public void addRenderingHints(Map hints) + { + // TODO: Implement this method + } + + @Override + public void clip(Shape s) + { + // TODO: Implement this method + } + + @Override + public void draw(Shape s) + { + // TODO: Implement this method + } + + @Override + public void drawGlyphVector(GlyphVector g, float x, float y) + { + // TODO: Implement this method + } + + @Override + public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) + { + // TODO: Implement this method + } + + @Override + public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) + { + // TODO: Implement this method + return false; + } + + @Override + public void drawRenderableImage(RenderableImage img, AffineTransform xform) + { + // TODO: Implement this method + } + + @Override + public void drawRenderedImage(RenderedImage img, AffineTransform xform) + { + // TODO: Implement this method + } + + @Override + public void drawString(AttributedCharacterIterator iterator, float x, float y) + { + // TODO: Implement this method + } + + @Override + public void drawString(AttributedCharacterIterator iterator, int x, int y) + { + // TODO: Implement this method + } + + @Override + public void drawString(String s, float x, float y) + { + // TODO: Implement this method + } + + @Override + public void drawString(String str, int x, int y) + { + // TODO: Implement this method + } + + @Override + public void fill(Shape s) + { + // TODO: Implement this method + } + + @Override + public Color getBackground() + { + // TODO: Implement this method + return null; + } + + @Override + public Composite getComposite() + { + // TODO: Implement this method + return null; + } + + @Override + public GraphicsConfiguration getDeviceConfiguration() + { + // TODO: Implement this method + return null; + } + + @Override + public FontRenderContext getFontRenderContext() + { + // TODO: Implement this method + return null; + } + + @Override + public Paint getPaint() + { + // TODO: Implement this method + return null; + } + + @Override + public Object getRenderingHint(RenderingHints.Key key) + { + // TODO: Implement this method + return null; + } + + @Override + public RenderingHints getRenderingHints() + { + // TODO: Implement this method + return null; + } + + @Override + public Stroke getStroke() + { + // TODO: Implement this method + return null; + } + + @Override + public AffineTransform getTransform() + { + // TODO: Implement this method + return null; + } + + @Override + public boolean hit(Rectangle rect, Shape s, boolean onStroke) + { + // TODO: Implement this method + return false; + } + + @Override + public void rotate(double theta) + { + // TODO: Implement this method + } + + @Override + public void rotate(double theta, double x, double y) + { + // TODO: Implement this method + } + + @Override + public void scale(double sx, double sy) + { + // TODO: Implement this method + } + + @Override + public void setBackground(Color color) + { + // TODO: Implement this method + } + + @Override + public void setComposite(Composite comp) + { + // TODO: Implement this method + } + + @Override + public void setPaint(Paint paint) + { + // TODO: Implement this method + } + + @Override + public void setRenderingHint(RenderingHints.Key key, Object value) + { + // TODO: Implement this method + } + + @Override + public void setRenderingHints(Map hints) + { + // TODO: Implement this method + } + + @Override + public void setStroke(Stroke s) + { + // TODO: Implement this method + } + + @Override + public void setTransform(AffineTransform Tx) + { + // TODO: Implement this method + } + + @Override + public void shear(double shx, double shy) + { + // TODO: Implement this method + } + + @Override + public void transform(AffineTransform Tx) + { + // TODO: Implement this method + } + + @Override + public void translate(double tx, double ty) + { + // TODO: Implement this method + } + + @Override + public void translate(int x, int y) + { + // TODO: Implement this method + } + +} diff --git a/app/src/main/java/java/awt/AWTEvent.java b/app/src/main/java/java/awt/AWTEvent.java new file mode 100644 index 000000000..a8dc83aaf --- /dev/null +++ b/app/src/main/java/java/awt/AWTEvent.java @@ -0,0 +1,681 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Dmitry A. Durnev, Michael Danilov + * @version $Revision$ + */ + +package java.awt; + +import java.util.EventObject; +import java.util.Hashtable; +import java.util.EventListener; + +import java.awt.event.*; + +/** + * The abstract class AWTEvent is the base class for all AWT events. This class + * and its subclasses supersede the original java.awt.Event class. + * + * @since Android 1.0 + */ +public abstract class AWTEvent extends EventObject { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = -1825314779160409405L; + + /** + * The Constant COMPONENT_EVENT_MASK indicates the event relates to a + * component. + */ + public static final long COMPONENT_EVENT_MASK = 1; + + /** + * The Constant CONTAINER_EVENT_MASK indicates the event relates to a + * container. + */ + public static final long CONTAINER_EVENT_MASK = 2; + + /** + * The Constant FOCUS_EVENT_MASK indicates the event relates to the focus. + */ + public static final long FOCUS_EVENT_MASK = 4; + + /** + * The Constant KEY_EVENT_MASK indicates the event relates to a key. + */ + public static final long KEY_EVENT_MASK = 8; + + /** + * The Constant MOUSE_EVENT_MASK indicates the event relates to the mouse. + */ + public static final long MOUSE_EVENT_MASK = 16; + + /** + * The Constant MOUSE_MOTION_EVENT_MASK indicates the event relates to a + * mouse motion. + */ + public static final long MOUSE_MOTION_EVENT_MASK = 32; + + /** + * The Constant WINDOW_EVENT_MASK indicates the event relates to a window. + */ + public static final long WINDOW_EVENT_MASK = 64; + + /** + * The Constant ACTION_EVENT_MASK indicates the event relates to an action. + */ + public static final long ACTION_EVENT_MASK = 128; + + /** + * The Constant ADJUSTMENT_EVENT_MASK indicates the event relates to an + * adjustment. + */ + public static final long ADJUSTMENT_EVENT_MASK = 256; + + /** + * The Constant ITEM_EVENT_MASK indicates the event relates to an item. + */ + public static final long ITEM_EVENT_MASK = 512; + + /** + * The Constant TEXT_EVENT_MASK indicates the event relates to text. + */ + public static final long TEXT_EVENT_MASK = 1024; + + /** + * The Constant INPUT_METHOD_EVENT_MASK indicates the event relates to an + * input method. + */ + public static final long INPUT_METHOD_EVENT_MASK = 2048; + + /** + * The Constant PAINT_EVENT_MASK indicates the event relates to a paint + * method. + */ + public static final long PAINT_EVENT_MASK = 8192; + + /** + * The Constant INVOCATION_EVENT_MASK indicates the event relates to a + * method invocation. + */ + public static final long INVOCATION_EVENT_MASK = 16384; + + /** + * The Constant HIERARCHY_EVENT_MASK indicates the event relates to a + * hierarchy. + */ + public static final long HIERARCHY_EVENT_MASK = 32768; + + /** + * The Constant HIERARCHY_BOUNDS_EVENT_MASK indicates the event relates to + * hierarchy bounds. + */ + public static final long HIERARCHY_BOUNDS_EVENT_MASK = 65536; + + /** + * The Constant MOUSE_WHEEL_EVENT_MASK indicates the event relates to the + * mouse wheel. + */ + public static final long MOUSE_WHEEL_EVENT_MASK = 131072; + + /** + * The Constant WINDOW_STATE_EVENT_MASK indicates the event relates to a + * window state. + */ + public static final long WINDOW_STATE_EVENT_MASK = 262144; + + /** + * The Constant WINDOW_FOCUS_EVENT_MASK indicates the event relates to a + * window focus. + */ + public static final long WINDOW_FOCUS_EVENT_MASK = 524288; + + /** + * The Constant RESERVED_ID_MAX indicates the maximum value for reserved AWT + * event IDs. + */ + public static final int RESERVED_ID_MAX = 1999; + + /** + * The Constant eventsMap. + */ + private static final Hashtable eventsMap = new Hashtable(); + + /** + * The converter. + */ + private static EventConverter converter; + + /** + * The ID of the event. + */ + protected int id; + + /** + * The consumed indicates whether or not the event is sent back down to the + * peer once the source has processed it (false means it's sent to the peer, + * true means it's not). + */ + protected boolean consumed; + + /** + * The dispatched by kfm. + */ + boolean dispatchedByKFM; + + /** + * The is posted. + */ + transient boolean isPosted; + + static { + eventsMap.put(new Integer(KeyEvent.KEY_TYPED), new EventDescriptor(KEY_EVENT_MASK, + KeyListener.class)); + eventsMap.put(new Integer(KeyEvent.KEY_PRESSED), new EventDescriptor(KEY_EVENT_MASK, + KeyListener.class)); + eventsMap.put(new Integer(KeyEvent.KEY_RELEASED), new EventDescriptor(KEY_EVENT_MASK, + KeyListener.class)); + eventsMap.put(new Integer(MouseEvent.MOUSE_CLICKED), new EventDescriptor(MOUSE_EVENT_MASK, + MouseListener.class)); + eventsMap.put(new Integer(MouseEvent.MOUSE_PRESSED), new EventDescriptor(MOUSE_EVENT_MASK, + MouseListener.class)); + eventsMap.put(new Integer(MouseEvent.MOUSE_RELEASED), new EventDescriptor(MOUSE_EVENT_MASK, + MouseListener.class)); + eventsMap.put(new Integer(MouseEvent.MOUSE_MOVED), new EventDescriptor( + MOUSE_MOTION_EVENT_MASK, MouseMotionListener.class)); + eventsMap.put(new Integer(MouseEvent.MOUSE_ENTERED), new EventDescriptor(MOUSE_EVENT_MASK, + MouseListener.class)); + eventsMap.put(new Integer(MouseEvent.MOUSE_EXITED), new EventDescriptor(MOUSE_EVENT_MASK, + MouseListener.class)); + eventsMap.put(new Integer(MouseEvent.MOUSE_DRAGGED), new EventDescriptor( + MOUSE_MOTION_EVENT_MASK, MouseMotionListener.class)); + eventsMap.put(new Integer(MouseEvent.MOUSE_WHEEL), new EventDescriptor( + MOUSE_WHEEL_EVENT_MASK, MouseWheelListener.class)); + eventsMap.put(new Integer(ComponentEvent.COMPONENT_MOVED), new EventDescriptor( + COMPONENT_EVENT_MASK, ComponentListener.class)); + eventsMap.put(new Integer(ComponentEvent.COMPONENT_RESIZED), new EventDescriptor( + COMPONENT_EVENT_MASK, ComponentListener.class)); + eventsMap.put(new Integer(ComponentEvent.COMPONENT_SHOWN), new EventDescriptor( + COMPONENT_EVENT_MASK, ComponentListener.class)); + eventsMap.put(new Integer(ComponentEvent.COMPONENT_HIDDEN), new EventDescriptor( + COMPONENT_EVENT_MASK, ComponentListener.class)); + eventsMap.put(new Integer(FocusEvent.FOCUS_GAINED), new EventDescriptor(FOCUS_EVENT_MASK, + FocusListener.class)); + eventsMap.put(new Integer(FocusEvent.FOCUS_LOST), new EventDescriptor(FOCUS_EVENT_MASK, + FocusListener.class)); + eventsMap.put(new Integer(PaintEvent.PAINT), new EventDescriptor(PAINT_EVENT_MASK, null)); + eventsMap.put(new Integer(PaintEvent.UPDATE), new EventDescriptor(PAINT_EVENT_MASK, null)); + eventsMap.put(new Integer(WindowEvent.WINDOW_OPENED), new EventDescriptor( + WINDOW_EVENT_MASK, WindowListener.class)); + eventsMap.put(new Integer(WindowEvent.WINDOW_CLOSING), new EventDescriptor( + WINDOW_EVENT_MASK, WindowListener.class)); + eventsMap.put(new Integer(WindowEvent.WINDOW_CLOSED), new EventDescriptor( + WINDOW_EVENT_MASK, WindowListener.class)); + eventsMap.put(new Integer(WindowEvent.WINDOW_DEICONIFIED), new EventDescriptor( + WINDOW_EVENT_MASK, WindowListener.class)); + eventsMap.put(new Integer(WindowEvent.WINDOW_ICONIFIED), new EventDescriptor( + WINDOW_EVENT_MASK, WindowListener.class)); + eventsMap.put(new Integer(WindowEvent.WINDOW_STATE_CHANGED), new EventDescriptor( + WINDOW_STATE_EVENT_MASK, WindowStateListener.class)); + eventsMap.put(new Integer(WindowEvent.WINDOW_LOST_FOCUS), new EventDescriptor( + WINDOW_FOCUS_EVENT_MASK, WindowFocusListener.class)); + eventsMap.put(new Integer(WindowEvent.WINDOW_GAINED_FOCUS), new EventDescriptor( + WINDOW_FOCUS_EVENT_MASK, WindowFocusListener.class)); + eventsMap.put(new Integer(WindowEvent.WINDOW_DEACTIVATED), new EventDescriptor( + WINDOW_EVENT_MASK, WindowListener.class)); + eventsMap.put(new Integer(WindowEvent.WINDOW_ACTIVATED), new EventDescriptor( + WINDOW_EVENT_MASK, WindowListener.class)); + eventsMap.put(new Integer(HierarchyEvent.HIERARCHY_CHANGED), new EventDescriptor( + HIERARCHY_EVENT_MASK, HierarchyListener.class)); + eventsMap.put(new Integer(HierarchyEvent.ANCESTOR_MOVED), new EventDescriptor( + HIERARCHY_BOUNDS_EVENT_MASK, HierarchyBoundsListener.class)); + eventsMap.put(new Integer(HierarchyEvent.ANCESTOR_RESIZED), new EventDescriptor( + HIERARCHY_BOUNDS_EVENT_MASK, HierarchyBoundsListener.class)); + eventsMap.put(new Integer(ContainerEvent.COMPONENT_ADDED), new EventDescriptor( + CONTAINER_EVENT_MASK, ContainerListener.class)); + eventsMap.put(new Integer(ContainerEvent.COMPONENT_REMOVED), new EventDescriptor( + CONTAINER_EVENT_MASK, ContainerListener.class)); + eventsMap.put(new Integer(InputMethodEvent.INPUT_METHOD_TEXT_CHANGED), new EventDescriptor( + INPUT_METHOD_EVENT_MASK, InputMethodListener.class)); + eventsMap.put(new Integer(InputMethodEvent.CARET_POSITION_CHANGED), new EventDescriptor( + INPUT_METHOD_EVENT_MASK, InputMethodListener.class)); + eventsMap.put(new Integer(InvocationEvent.INVOCATION_DEFAULT), new EventDescriptor( + INVOCATION_EVENT_MASK, null)); + eventsMap.put(new Integer(ItemEvent.ITEM_STATE_CHANGED), new EventDescriptor( + ITEM_EVENT_MASK, ItemListener.class)); + eventsMap.put(new Integer(TextEvent.TEXT_VALUE_CHANGED), new EventDescriptor( + TEXT_EVENT_MASK, TextListener.class)); + eventsMap.put(new Integer(ActionEvent.ACTION_PERFORMED), new EventDescriptor( + ACTION_EVENT_MASK, ActionListener.class)); + eventsMap.put(new Integer(AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED), new EventDescriptor( + ADJUSTMENT_EVENT_MASK, AdjustmentListener.class)); + converter = new EventConverter(); + } + + /** + * Instantiates a new AWT event from the specified Event object. + * + * @param event + * the Event object. + */ + public AWTEvent(Event event) { + this(event.target, event.id); + } + + /** + * Instantiates a new AWT event with the specified object and type. + * + * @param source + * the source Object. + * @param id + * the event's type. + */ + public AWTEvent(Object source, int id) { + super(source); + this.id = id; + consumed = false; + } + + /** + * Gets the event's type. + * + * @return the event type ID. + */ + public int getID() { + return id; + } + + /** + * Sets a new source for the AWTEvent. + * + * @param newSource + * the new source Object for the AWTEvent. + */ + public void setSource(Object newSource) { + source = newSource; + } + + /** + * Returns a String representation of the AWTEvent. + * + * @return the String representation of the AWTEvent. + */ + @Override + public String toString() { + /* + * The format is based on 1.5 release behavior which can be revealed by + * the following code: AWTEvent event = new AWTEvent(new Component(){}, + * 1){}; System.out.println(event); + */ + String name = ""; //$NON-NLS-1$ + + if (source instanceof Component && (source != null)) { + Component comp = (Component)getSource(); + name = comp.getName(); + if (name == null) { + name = ""; //$NON-NLS-1$ + } + } + + return (getClass().getName() + "[" + paramString() + "]" //$NON-NLS-1$ //$NON-NLS-2$ + + " on " + (name.length() > 0 ? name : source)); //$NON-NLS-1$ + } + + /** + * Returns a string representation of the AWTEvent state. + * + * @return a string representation of the AWTEvent state. + */ + public String paramString() { + // nothing to implement: all event types must override this method + return ""; //$NON-NLS-1$ + } + + /** + * Checks whether or not this AWTEvent has been consumed. + * + * @return true, if this AWTEvent has been consumed, false otherwise. + */ + protected boolean isConsumed() { + return consumed; + } + + /** + * Consumes the AWTEvent. + */ + protected void consume() { + consumed = true; + } + + /** + * Convert AWTEvent object to a corresponding (deprecated) Event object. + * + * @return new Event object which is a converted AWTEvent object or null if + * the conversion is not possible + */ + Event getEvent() { + + if (id == ActionEvent.ACTION_PERFORMED) { + ActionEvent ae = (ActionEvent)this; + return converter.convertActionEvent(ae); + + } else if (id == AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED) { + AdjustmentEvent ae = (AdjustmentEvent)this; + return converter.convertAdjustmentEvent(ae); + + // ???AWT + // } else if (id == ComponentEvent.COMPONENT_MOVED + // && source instanceof Window) { + // //the only type of Component events is COMPONENT_MOVED on window + // ComponentEvent ce = (ComponentEvent) this; + // return converter.convertComponentEvent(ce); + + } else if (id >= FocusEvent.FOCUS_FIRST && id <= FocusEvent.FOCUS_LAST) { + // nothing to convert + + // ???AWT + // } else if (id == ItemEvent.ITEM_STATE_CHANGED) { + // ItemEvent ie = (ItemEvent) this; + // return converter.convertItemEvent(ie); + + } else if (id == KeyEvent.KEY_PRESSED || id == KeyEvent.KEY_RELEASED) { + KeyEvent ke = (KeyEvent)this; + return converter.convertKeyEvent(ke); + } else if (id >= MouseEvent.MOUSE_FIRST && id <= MouseEvent.MOUSE_LAST) { + MouseEvent me = (MouseEvent)this; + return converter.convertMouseEvent(me); + } else if (id == WindowEvent.WINDOW_CLOSING || id == WindowEvent.WINDOW_ICONIFIED + || id == WindowEvent.WINDOW_DEICONIFIED) { + // nothing to convert + } else { + return null; + } + return new Event(source, id, null); + } + + /** + * The class EventDescriptor. + */ + static final class EventDescriptor { + + /** + * The event mask. + */ + final long eventMask; + + /** + * The listener type. + */ + final Class listenerType; + + /** + * Instantiates a new event descriptor. + * + * @param eventMask + * the event mask. + * @param listenerType + * the listener type. + */ + EventDescriptor(long eventMask, Class listenerType) { + this.eventMask = eventMask; + this.listenerType = listenerType; + } + + } + + /** + * The class EventTypeLookup. + */ + static final class EventTypeLookup { + + /** + * The last event. + */ + private AWTEvent lastEvent = null; + + /** + * The last event descriptor. + */ + private EventDescriptor lastEventDescriptor = null; + + /** + * Gets the event descriptor. + * + * @param event + * the event. + * @return the event descriptor. + */ + EventDescriptor getEventDescriptor(AWTEvent event) { + synchronized (this) { + if (event != lastEvent) { + lastEvent = event; + lastEventDescriptor = eventsMap.get(new Integer(event.id)); + } + + return lastEventDescriptor; + } + } + + /** + * Gets the event mask. + * + * @param event + * the event. + * @return the event mask. + */ + long getEventMask(AWTEvent event) { + final EventDescriptor ed = getEventDescriptor(event); + return ed == null ? -1 : ed.eventMask; + } + } + + /** + * The class EventConverter. + */ + static final class EventConverter { + + /** + * The constant OLD_MOD_MASK. + */ + static final int OLD_MOD_MASK = Event.ALT_MASK | Event.CTRL_MASK | Event.META_MASK + | Event.SHIFT_MASK; + + /** + * Convert action event. + * + * @param ae + * the ae. + * @return the event. + */ + Event convertActionEvent(ActionEvent ae) { + Event evt = new Event(ae.getSource(), ae.getID(), ae.getActionCommand()); + evt.when = ae.getWhen(); + evt.modifiers = ae.getModifiers() & OLD_MOD_MASK; + + /* + * if (source instanceof Button) { arg = ((Button) + * source).getLabel(); } else if (source instanceof Checkbox) { arg + * = new Boolean(((Checkbox) source).getState()); } else if (source + * instanceof CheckboxMenuItem) { arg = ((CheckboxMenuItem) + * source).getLabel(); } else if (source instanceof Choice) { arg = + * ((Choice) source).getSelectedItem(); } else if (source instanceof + * List) { arg = ((List) source).getSelectedItem(); } else if + * (source instanceof MenuItem) { arg = ((MenuItem) + * source).getLabel(); } else if (source instanceof TextField) { arg + * = ((TextField) source).getText(); } + */ + return evt; + } + + /** + * Convert adjustment event. + * + * @param ae + * the ae. + * @return the event. + */ + Event convertAdjustmentEvent(AdjustmentEvent ae) { + // TODO: Event.SCROLL_BEGIN/SCROLL_END + return new Event(ae.source, ae.id + ae.getAdjustmentType() - 1, new Integer(ae + .getValue())); + } + + /** + * Convert component event. + * + * @param ce + * the ce. + * @return the event. + */ + Event convertComponentEvent(ComponentEvent ce) { + Component comp = ce.getComponent(); + Event evt = new Event(comp, Event.WINDOW_MOVED, null); + evt.x = comp.getX(); + evt.y = comp.getY(); + return evt; + } + + // ???AWT + /* + * Event convertItemEvent(ItemEvent ie) { int oldId = ie.id + + * ie.getStateChange() - 1; Object source = ie.source; int idx = -1; if + * (source instanceof List) { List list = (List) source; idx = + * list.getSelectedIndex(); } else if (source instanceof Choice) { + * Choice choice = (Choice) source; idx = choice.getSelectedIndex(); } + * Object arg = idx >= 0 ? new Integer(idx) : null; return new + * Event(source, oldId, arg); } + */ + + /** + * Convert key event. + * + * @param ke + * the ke. + * @return the event. + */ + Event convertKeyEvent(KeyEvent ke) { + int oldId = ke.id; + // leave only old Event's modifiers + + int mod = ke.getModifiers() & OLD_MOD_MASK; + Component comp = ke.getComponent(); + char keyChar = ke.getKeyChar(); + int keyCode = ke.getKeyCode(); + int key = convertKey(keyChar, keyCode); + if (key >= Event.HOME && key <= Event.INSERT) { + oldId += 2; // non-ASCII key -> action key + } + return new Event(comp, ke.getWhen(), oldId, 0, 0, key, mod); + } + + /** + * Convert mouse event. + * + * @param me + * the me. + * @return the event. + */ + Event convertMouseEvent(MouseEvent me) { + int id = me.id; + if (id != MouseEvent.MOUSE_CLICKED) { + Event evt = new Event(me.source, id, null); + evt.x = me.getX(); + evt.y = me.getY(); + int mod = me.getModifiers(); + // in Event modifiers mean button number for mouse events: + evt.modifiers = mod & (Event.ALT_MASK | Event.META_MASK); + if (id == MouseEvent.MOUSE_PRESSED) { + evt.clickCount = me.getClickCount(); + } + return evt; + } + return null; + } + + /** + * Convert key. + * + * @param keyChar + * the key char. + * @param keyCode + * the key code. + * @return the int. + */ + int convertKey(char keyChar, int keyCode) { + int key; + // F1 - F12 + if (keyCode >= KeyEvent.VK_F1 && keyCode <= KeyEvent.VK_F12) { + key = Event.F1 + keyCode - KeyEvent.VK_F1; + } else { + switch (keyCode) { + default: // non-action key + key = keyChar; + break; + // action keys: + case KeyEvent.VK_HOME: + key = Event.HOME; + break; + case KeyEvent.VK_END: + key = Event.END; + break; + case KeyEvent.VK_PAGE_UP: + key = Event.PGUP; + break; + case KeyEvent.VK_PAGE_DOWN: + key = Event.PGDN; + break; + case KeyEvent.VK_UP: + key = Event.UP; + break; + case KeyEvent.VK_DOWN: + key = Event.DOWN; + break; + case KeyEvent.VK_LEFT: + key = Event.LEFT; + break; + case KeyEvent.VK_RIGHT: + key = Event.RIGHT; + break; + case KeyEvent.VK_PRINTSCREEN: + key = Event.PRINT_SCREEN; + break; + case KeyEvent.VK_SCROLL_LOCK: + key = Event.SCROLL_LOCK; + break; + case KeyEvent.VK_CAPS_LOCK: + key = Event.CAPS_LOCK; + break; + case KeyEvent.VK_NUM_LOCK: + key = Event.NUM_LOCK; + break; + case KeyEvent.VK_PAUSE: + key = Event.PAUSE; + break; + case KeyEvent.VK_INSERT: + key = Event.INSERT; + break; + } + } + return key; + } + + } + +} diff --git a/app/src/main/java/java/awt/AWTKeyStroke.java b/app/src/main/java/java/awt/AWTKeyStroke.java new file mode 100644 index 000000000..f01f6f00e --- /dev/null +++ b/app/src/main/java/java/awt/AWTKeyStroke.java @@ -0,0 +1,712 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Dmitry A. Durnev + * @version $Revision$ + */ + +package java.awt; + +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.io.ObjectStreamException; +import java.io.Serializable; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.StringTokenizer; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The AWTKeyStroke holds all of the information for the complete act of + * typing a character. This includes the events that are generated when + * the key is pressed, released, or typed (pressed and released generating + * a Unicode character result) which are associated with the event + * objects KeyEvent.KEY_PRESSED, KeyEvent.KEY_RELEASED, or KeyEvent.KEY_TYPED. + * It also holds information about which modifiers (such as control or + * shift) were used in conjunction with the keystroke. The following masks + * are available to identify the modifiers: + *
    + *
  • java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK
  • + *
  • java.awt.event.InputEvent.ALT_DOWN_MASK
  • + *
  • java.awt.event.InputEvent.CTRL_DOWN_MASK
  • + *
  • java.awt.event.InputEvent.META_DOWN_MASK
  • + *
  • java.awt.event.InputEvent.SHIFT_DOWN_MASK
  • + *
  • java.awt.event.InputEvent.ALT_GRAPH_MASK
  • + *
  • java.awt.event.InputEvent.ALT_MASK
  • + *
  • java.awt.event.InputEvent.CTRL_MASK
  • + *
  • java.awt.event.InputEvent.META_MASK
  • + *
  • java.awt.event.InputEvent.SHIFT_MASK
  • + *
+ *
+ * The AWTKeyStroke is unique, and applications should not create their own + * instances of AWTKeyStroke. All applications should use getAWTKeyStroke + * methods for obtaining instances of AWTKeyStroke. + * + * @since Android 1.0 + */ +public class AWTKeyStroke implements Serializable { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = -6430539691155161871L; + + /** + * The Constant cache. + */ + private static final Map cache = new HashMap(); // Map + + // < + // AWTKeyStroke + // , + // ? + // extends + // AWTKeyStroke + // > + + /** + * The Constant keyEventTypesMap. + */ + private static final Map keyEventTypesMap = new HashMap(); // Map + + // < + // int + // , + // String + // > + + private static Constructor subConstructor; + + static { + keyEventTypesMap.put(new Integer(KeyEvent.KEY_PRESSED), "pressed"); //$NON-NLS-1$ + keyEventTypesMap.put(new Integer(KeyEvent.KEY_RELEASED), "released"); //$NON-NLS-1$ + keyEventTypesMap.put(new Integer(KeyEvent.KEY_TYPED), "typed"); //$NON-NLS-1$ + } + + /** + * The key char. + */ + private char keyChar; + + /** + * The key code. + */ + private int keyCode; + + /** + * The modifiers. + */ + private int modifiers; + + /** + * The on key release. + */ + private boolean onKeyRelease; + + /** + * Instantiates a new AWTKeyStroke. getAWTKeyStroke method should be used by + * applications code. + * + * @param keyChar + * the key char. + * @param keyCode + * the key code. + * @param modifiers + * the modifiers. + * @param onKeyRelease + * true if AWTKeyStroke is for a key release, false otherwise. + */ + protected AWTKeyStroke(char keyChar, int keyCode, int modifiers, boolean onKeyRelease) { + setAWTKeyStroke(keyChar, keyCode, modifiers, onKeyRelease); + } + + /** + * Sets the AWT key stroke. + * + * @param keyChar + * the key char. + * @param keyCode + * the key code. + * @param modifiers + * the modifiers. + * @param onKeyRelease + * the on key release. + */ + private void setAWTKeyStroke(char keyChar, int keyCode, int modifiers, boolean onKeyRelease) { + this.keyChar = keyChar; + this.keyCode = keyCode; + this.modifiers = modifiers; + this.onKeyRelease = onKeyRelease; + } + + /** + * Instantiates a new AWTKeyStroke with default parameters: + * KeyEvent.CHAR_UNDEFINED key char, KeyEvent.VK_UNDEFINED key code, without + * modifiers and false key realized value. + */ + protected AWTKeyStroke() { + this(KeyEvent.CHAR_UNDEFINED, KeyEvent.VK_UNDEFINED, 0, false); + } + + /** + * Returns the unique number value for AWTKeyStroke object. + * + * @return the integer unique value of the AWTKeyStroke object. + */ + @Override + public int hashCode() { + return modifiers + (keyCode != KeyEvent.VK_UNDEFINED ? keyCode : keyChar) + + (onKeyRelease ? -1 : 0); + } + + /** + * Gets the set of modifiers for the AWTKeyStroke object. + * + * @return the integer value which contains modifiers. + */ + public final int getModifiers() { + return modifiers; + } + + /** + * Compares this AWTKeyStroke object to the specified object. + * + * @param anObject + * the specified AWTKeyStroke object to compare with this + * instance. + * @return true if objects are identical, false otherwise. + */ + @Override + public final boolean equals(Object anObject) { + if (anObject instanceof AWTKeyStroke) { + AWTKeyStroke key = (AWTKeyStroke)anObject; + return ((key.keyCode == keyCode) && (key.keyChar == keyChar) + && (key.modifiers == modifiers) && (key.onKeyRelease == onKeyRelease)); + } + return false; + } + + /** + * Returns the string representation of the AWTKeyStroke. This string should + * contain key stroke properties. + * + * @return the string representation of the AWTKeyStroke. + */ + @Override + public String toString() { + int type = getKeyEventType(); + return InputEvent.getModifiersExText(getModifiers()) + " " + //$NON-NLS-1$ + keyEventTypesMap.get(new Integer(type)) + " " + //$NON-NLS-1$ + (type == KeyEvent.KEY_TYPED ? new String(new char[] { + keyChar + }) : KeyEvent.getKeyText(keyCode)); + } + + /** + * Gets the key code for the AWTKeyStroke object. + * + * @return the key code for the AWTKeyStroke object. + */ + public final int getKeyCode() { + return keyCode; + } + + /** + * Gets the key character for the AWTKeyStroke object. + * + * @return the key character for the AWTKeyStroke object. + */ + public final char getKeyChar() { + return keyChar; + } + + /** + * Gets the AWT key stroke. + * + * @param keyChar + * the key char. + * @param keyCode + * the key code. + * @param modifiers + * the modifiers. + * @param onKeyRelease + * the on key release. + * @return the AWT key stroke. + */ + private static AWTKeyStroke getAWTKeyStroke(char keyChar, int keyCode, int modifiers, + boolean onKeyRelease) { + AWTKeyStroke key = newInstance(keyChar, keyCode, modifiers, onKeyRelease); + + AWTKeyStroke value = cache.get(key); + if (value == null) { + value = key; + cache.put(key, value); + } + return value; + } + + /** + * New instance. + * + * @param keyChar + * the key char. + * @param keyCode + * the key code. + * @param modifiers + * the modifiers. + * @param onKeyRelease + * the on key release. + * @return the AWT key stroke. + */ + private static AWTKeyStroke newInstance(char keyChar, int keyCode, int modifiers, + boolean onKeyRelease) { + AWTKeyStroke key; + // ???AWT + // if (subConstructor == null) { + key = new AWTKeyStroke(); + // ???AWT + // } else { + // try { + // key = (AWTKeyStroke) subConstructor.newInstance(); + // } catch (Exception e) { + // throw new RuntimeException(e); + // } + // } + int allModifiers = getAllModifiers(modifiers); + key.setAWTKeyStroke(keyChar, keyCode, allModifiers, onKeyRelease); + return key; + } + + /** + * Adds the mask. + * + * @param mod + * the mod. + * @param mask + * the mask. + * @return the int. + */ + private static int addMask(int mod, int mask) { + return ((mod & mask) != 0) ? (mod | mask) : mod; + } + + /** + * Return all (old & new) modifiers corresponding to. + * + * @param mod + * old or new modifiers. + * @return old and new modifiers together. + */ + static int getAllModifiers(int mod) { + int allMod = mod; + int shift = (InputEvent.SHIFT_MASK | InputEvent.SHIFT_DOWN_MASK); + int ctrl = (InputEvent.CTRL_MASK | InputEvent.CTRL_DOWN_MASK); + int meta = (InputEvent.META_MASK | InputEvent.META_DOWN_MASK); + int alt = (InputEvent.ALT_MASK | InputEvent.ALT_DOWN_MASK); + int altGr = (InputEvent.ALT_GRAPH_MASK | InputEvent.ALT_GRAPH_DOWN_MASK); + // button modifiers are not converted between old & new + + allMod = addMask(allMod, shift); + allMod = addMask(allMod, ctrl); + allMod = addMask(allMod, meta); + allMod = addMask(allMod, alt); + allMod = addMask(allMod, altGr); + + return allMod; + } + + /** + * Returns an instance of AWTKeyStroke for parsed string. The string must + * have the following syntax: + *

+ * <modifiers>* (<typedID> | <pressedReleasedID>) + *

+ * modifiers := shift | control | ctrl | meta | alt | altGraph
+ * typedID := typed
+ * typedKey := string of length 1 giving the Unicode character.
+ * pressedReleasedID := (pressed | released)
+ * key := KeyEvent key code name, i.e. the name following "VK_". + *

+ * + * @param s + * the String which contains key stroke parameters. + * @return the AWTKeyStroke for string. + * @throws IllegalArgumentException + * if string has incorrect format or null. + */ + public static AWTKeyStroke getAWTKeyStroke(String s) { + if (s == null) { + // awt.65=null argument + throw new IllegalArgumentException(Messages.getString("awt.65")); //$NON-NLS-1$ + } + + StringTokenizer tokenizer = new StringTokenizer(s); + + Boolean release = null; + int modifiers = 0; + int keyCode = KeyEvent.VK_UNDEFINED; + char keyChar = KeyEvent.CHAR_UNDEFINED; + boolean typed = false; + long modifier = 0; + String token = null; + do { + token = getNextToken(tokenizer); + modifier = parseModifier(token); + modifiers |= modifier; + } while (modifier > 0); + + typed = parseTypedID(token); + + if (typed) { + token = getNextToken(tokenizer); + keyChar = parseTypedKey(token); + + } + if (keyChar == KeyEvent.CHAR_UNDEFINED) { + release = parsePressedReleasedID(token); + if (release != null) { + token = getNextToken(tokenizer); + } + keyCode = parseKey(token); + } + if (tokenizer.hasMoreTokens()) { + // awt.66=Invalid format + throw new IllegalArgumentException(Messages.getString("awt.66")); //$NON-NLS-1$ + } + + return getAWTKeyStroke(keyChar, keyCode, modifiers, release == Boolean.TRUE); + } + + /** + * Gets the next token. + * + * @param tokenizer + * the tokenizer. + * @return the next token. + */ + private static String getNextToken(StringTokenizer tokenizer) { + try { + return tokenizer.nextToken(); + } catch (NoSuchElementException exception) { + // awt.66=Invalid format + throw new IllegalArgumentException(Messages.getString("awt.66")); //$NON-NLS-1$ + } + } + + /** + * Gets the key code. + * + * @param s + * the s. + * @return the key code. + */ + static int getKeyCode(String s) { + try { + Field vk = KeyEvent.class.getField("VK_" + s); //$NON-NLS-1$ + return vk.getInt(null); + } catch (Exception e) { + if (s.length() != 1) { + // awt.66=Invalid format + throw new IllegalArgumentException(Messages.getString("awt.66")); //$NON-NLS-1$ + } + return KeyEvent.VK_UNDEFINED; + } + } + + /** + * Gets an instance of the AWTKeyStroke for specified character. + * + * @param keyChar + * the keyboard character value. + * @return a AWTKeyStroke for specified character. + */ + public static AWTKeyStroke getAWTKeyStroke(char keyChar) { + return getAWTKeyStroke(keyChar, KeyEvent.VK_UNDEFINED, 0, false); + } + + /** + * Returns an instance of AWTKeyStroke for a given key code, set of + * modifiers, and specified key released flag value. The key codes are + * defined in java.awt.event.KeyEvent class. The set of modifiers is given + * as a bitwise combination of masks taken from the following list: + *

    + *
  • java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK
  • + * java.awt.event.InputEvent.ALT_DOWN_MASK
  • + * java.awt.event.InputEvent.CTRL_DOWN_MASK
  • + * java.awt.event.InputEvent.META_DOWN_MASK
  • + * java.awt.event.InputEvent.SHIFT_DOWN_MASK
  • + * java.awt.event.InputEvent.ALT_GRAPH_MASK
  • + * java.awt.event.InputEvent.ALT_MASK
  • + * java.awt.event.InputEvent.CTRL_MASK
  • + * java.awt.event.InputEvent.META_MASK
  • + * java.awt.event.InputEvent.SHIFT_MASK
  • + *
+ *
+ * + * @param keyCode + * the specified key code of keyboard. + * @param modifiers + * the bit set of modifiers. + * @param onKeyRelease + * the value which represents whether this AWTKeyStroke shall + * represents a key release. + * @return the AWTKeyStroke. + */ + public static AWTKeyStroke getAWTKeyStroke(int keyCode, int modifiers, boolean onKeyRelease) { + return getAWTKeyStroke(KeyEvent.CHAR_UNDEFINED, keyCode, modifiers, onKeyRelease); + } + + /** + * Returns AWTKeyStroke for a specified character and set of modifiers. The + * set of modifiers is given as a bitwise combination of masks taken from + * the following list: + *
    + *
  • java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK
  • + * java.awt.event.InputEvent.ALT_DOWN_MASK
  • + * java.awt.event.InputEvent.CTRL_DOWN_MASK
  • + * java.awt.event.InputEvent.META_DOWN_MASK
  • + * java.awt.event.InputEvent.SHIFT_DOWN_MASK
  • + * java.awt.event.InputEvent.ALT_GRAPH_MASK
  • + * java.awt.event.InputEvent.ALT_MASK
  • + * java.awt.event.InputEvent.CTRL_MASK
  • + * java.awt.event.InputEvent.META_MASK
  • + * java.awt.event.InputEvent.SHIFT_MASK
  • + *
+ * + * @param keyChar + * the Character object which represents keyboard character + * value. + * @param modifiers + * the bit set of modifiers. + * @return the AWTKeyStroke object. + * @throws IllegalArgumentException + * if keyChar value is null. + */ + public static AWTKeyStroke getAWTKeyStroke(Character keyChar, int modifiers) { + if (keyChar == null) { + // awt.01='{0}' parameter is null + throw new IllegalArgumentException(Messages.getString("awt.01", "keyChar")); //$NON-NLS-1$ //$NON-NLS-2$ + } + return getAWTKeyStroke(keyChar.charValue(), KeyEvent.VK_UNDEFINED, modifiers, false); + } + + /** + * Returns an instance of AWTKeyStroke for a specified key code and set of + * modifiers. The key codes are defined in java.awt.event.KeyEvent class. + * The set of modifiers is given as a bitwise combination of masks taken + * from the following list: + *
    + *
  • java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK
  • + * java.awt.event.InputEvent.ALT_DOWN_MASK
  • + * java.awt.event.InputEvent.CTRL_DOWN_MASK
  • + * java.awt.event.InputEvent.META_DOWN_MASK
  • + * java.awt.event.InputEvent.SHIFT_DOWN_MASK
  • + * java.awt.event.InputEvent.ALT_GRAPH_MASK
  • + * java.awt.event.InputEvent.ALT_MASK
  • + * java.awt.event.InputEvent.CTRL_MASK
  • + * java.awt.event.InputEvent.META_MASK
  • + * java.awt.event.InputEvent.SHIFT_MASK
  • + *
+ * + * @param keyCode + * the specified key code of keyboard. + * @param modifiers + * the bit set of modifiers. + * @return the AWTKeyStroke. + */ + public static AWTKeyStroke getAWTKeyStroke(int keyCode, int modifiers) { + return getAWTKeyStroke(keyCode, modifiers, false); + } + + /** + * Gets the AWTKeyStroke for a key event. This method obtains the key char + * and key code from the specified key event. + * + * @param anEvent + * the key event which identifies the desired AWTKeyStroke. + * @return the AWTKeyStroke for the key event. + */ + public static AWTKeyStroke getAWTKeyStrokeForEvent(KeyEvent anEvent) { + int id = anEvent.getID(); + char undef = KeyEvent.CHAR_UNDEFINED; + char keyChar = (id == KeyEvent.KEY_TYPED ? anEvent.getKeyChar() : undef); + int keyCode = (keyChar == undef ? anEvent.getKeyCode() : KeyEvent.VK_UNDEFINED); + return getAWTKeyStroke(keyChar, keyCode, anEvent.getModifiersEx(), + id == KeyEvent.KEY_RELEASED); + } + + /** + * Gets the key event type for the AWTKeyStroke object. + * + * @return the key event type: KeyEvent.KEY_PRESSED, KeyEvent.KEY_TYPED, or + * KeyEvent.KEY_RELEASED. + */ + public final int getKeyEventType() { + if (keyCode == KeyEvent.VK_UNDEFINED) { + return KeyEvent.KEY_TYPED; + } + return (onKeyRelease ? KeyEvent.KEY_RELEASED : KeyEvent.KEY_PRESSED); + } + + /** + * Returns true if the key event is associated with the AWTKeyStroke is + * KEY_RELEASED, false otherwise. + * + * @return true, if if the key event associated with the AWTKeyStroke is + * KEY_RELEASED, false otherwise. + */ + public final boolean isOnKeyRelease() { + return onKeyRelease; + } + + /** + * Read resolve. + * + * @return the object. + * @throws ObjectStreamException + * the object stream exception. + */ + protected Object readResolve() throws ObjectStreamException { + return getAWTKeyStroke(this.keyChar, this.keyCode, this.modifiers, this.onKeyRelease); + } + + /** + * Register subclass. + * + * @param subclass + * the subclass. + */ + protected static void registerSubclass(Class subclass) { + // ???AWT + /* + * if (subclass == null) { // awt.01='{0}' parameter is null throw new + * IllegalArgumentException(Messages.getString("awt.01", "subclass")); + * //$NON-NLS-1$ //$NON-NLS-2$ } if (! + * AWTKeyStroke.class.isAssignableFrom(subclass)) { // awt.67=subclass + * is not derived from AWTKeyStroke throw new + * ClassCastException(Messages.getString("awt.67")); //$NON-NLS-1$ } try + * { subConstructor = subclass.getDeclaredConstructor(); + * subConstructor.setAccessible(true); } catch (SecurityException e) { + * throw new RuntimeException(e); } catch (NoSuchMethodException e) { // + * awt.68=subclass could not be instantiated throw new + * IllegalArgumentException(Messages.getString("awt.68")); //$NON-NLS-1$ + * } cache.clear(); //flush the cache + */ + } + + /** + * Parses the modifier. + * + * @param strMod + * the str mod. + * @return the long. + */ + private static long parseModifier(String strMod) { + long modifiers = 0l; + if (strMod.equals("shift")) { //$NON-NLS-1$ + modifiers |= InputEvent.SHIFT_DOWN_MASK; + } else if (strMod.equals("control") || strMod.equals("ctrl")) { //$NON-NLS-1$ //$NON-NLS-2$ + modifiers |= InputEvent.CTRL_DOWN_MASK; + } else if (strMod.equals("meta")) { //$NON-NLS-1$ + modifiers |= InputEvent.META_DOWN_MASK; + } else if (strMod.equals("alt")) { //$NON-NLS-1$ + modifiers |= InputEvent.ALT_DOWN_MASK; + } else if (strMod.equals("altGraph")) { //$NON-NLS-1$ + modifiers |= InputEvent.ALT_GRAPH_DOWN_MASK; + } else if (strMod.equals("button1")) { //$NON-NLS-1$ + modifiers |= InputEvent.BUTTON1_DOWN_MASK; + } else if (strMod.equals("button2")) { //$NON-NLS-1$ + modifiers |= InputEvent.BUTTON2_DOWN_MASK; + } else if (strMod.equals("button3")) { //$NON-NLS-1$ + modifiers |= InputEvent.BUTTON3_DOWN_MASK; + } + return modifiers; + } + + /** + * Parses the typed id. + * + * @param strTyped + * the str typed. + * @return true, if successful. + */ + private static boolean parseTypedID(String strTyped) { + if (strTyped.equals("typed")) { //$NON-NLS-1$ + return true; + } + + return false; + } + + /** + * Parses the typed key. + * + * @param strChar + * the str char. + * @return the char. + */ + private static char parseTypedKey(String strChar) { + char keyChar = KeyEvent.CHAR_UNDEFINED; + + if (strChar.length() != 1) { + // awt.66=Invalid format + throw new IllegalArgumentException(Messages.getString("awt.66")); //$NON-NLS-1$ + } + keyChar = strChar.charAt(0); + return keyChar; + } + + /** + * Parses the pressed released id. + * + * @param str + * the str. + * @return the boolean. + */ + private static Boolean parsePressedReleasedID(String str) { + + if (str.equals("pressed")) { //$NON-NLS-1$ + return Boolean.FALSE; + } else if (str.equals("released")) { //$NON-NLS-1$ + return Boolean.TRUE; + } + return null; + } + + /** + * Parses the key. + * + * @param strCode + * the str code. + * @return the int. + */ + private static int parseKey(String strCode) { + int keyCode = KeyEvent.VK_UNDEFINED; + + keyCode = getKeyCode(strCode); + + if (keyCode == KeyEvent.VK_UNDEFINED) { + // awt.66=Invalid format + throw new IllegalArgumentException(Messages.getString("awt.66")); //$NON-NLS-1$ + } + return keyCode; + } +} diff --git a/app/src/main/java/java/awt/AWTListenerList.java b/app/src/main/java/java/awt/AWTListenerList.java new file mode 100644 index 000000000..3327d63b5 --- /dev/null +++ b/app/src/main/java/java/awt/AWTListenerList.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.awt; + +import java.util.EventListener; + +import org.apache.harmony.awt.ListenerList; + +final class AWTListenerList extends ListenerList { + private static final long serialVersionUID = -2622077171532840953L; + + private final Component owner; + + AWTListenerList() { + super(); + this.owner = null; + } + + AWTListenerList(Component owner) { + super(); + this.owner = owner; + } + + @Override + public void addUserListener(T listener) { + super.addUserListener(listener); + + if (owner != null) { + owner.deprecatedEventHandler = false; + } + } +} diff --git a/app/src/main/java/java/awt/AWTPermission.java b/app/src/main/java/java/awt/AWTPermission.java new file mode 100644 index 000000000..4bd835777 --- /dev/null +++ b/app/src/main/java/java/awt/AWTPermission.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ + +package java.awt; + +import java.security.BasicPermission; + +/** + * The AWTPermission specifies the name of the permission and the corresponding + * action list. + * + * @since Android 1.0 + */ +public final class AWTPermission extends BasicPermission { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = 8890392402588814465L; + + /** + * Instantiates a new AWTPermission with defined name and actions. + * + * @param name + * the name of a new AWTPermission. + * @param actions + * the actions of a new AWTPermission. + */ + public AWTPermission(String name, String actions) { + super(name, actions); + } + + /** + * Instantiates a new AWT permission with the defined name. + * + * @param name + * the name of a new AWTPermission. + */ + public AWTPermission(String name) { + super(name); + } + +} diff --git a/app/src/main/java/java/awt/ActiveEvent.java b/app/src/main/java/java/awt/ActiveEvent.java new file mode 100644 index 000000000..704462390 --- /dev/null +++ b/app/src/main/java/java/awt/ActiveEvent.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ + +package java.awt; + +/** + * This interface defines events that know how to dispatch themselves. Such + * event can be placed upon the event queue and its dispatch method will be + * called when the event is dispatched. + * + * @since Android 1.0 + */ +public interface ActiveEvent { + + /** + * Dispatches the event to the listeners of the event's source, or does + * whatever it is this event is supposed to do. + */ + public void dispatch(); + +} diff --git a/app/src/main/java/java/awt/Adjustable.java b/app/src/main/java/java/awt/Adjustable.java new file mode 100644 index 000000000..baf80f7c7 --- /dev/null +++ b/app/src/main/java/java/awt/Adjustable.java @@ -0,0 +1,166 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ + +package java.awt; + +import java.awt.event.AdjustmentListener; + +/** + * The Adjustable interface represents an adjustable numeric value contained + * within a bounded range of values, such as the current location in scrollable + * region or the value of a gauge. + * + * @since Android 1.0 + */ +public interface Adjustable { + + /** + * The Constant HORIZONTAL indicates that the Adjustable's orientation is + * horizontal. + */ + public static final int HORIZONTAL = 0; + + /** + * The Constant VERTICAL indicates that the Adjustable's orientation is + * vertical. + */ + public static final int VERTICAL = 1; + + /** + * The Constant NO_ORIENTATION indicates that the Adjustable has no + * orientation. + */ + public static final int NO_ORIENTATION = 2; + + /** + * Gets the value of the Adjustable. + * + * @return the current value of the Adjustable. + */ + public int getValue(); + + /** + * Sets the value to the Adjustable object. + * + * @param a0 + * the new value of the Adjustable object. + */ + public void setValue(int a0); + + /** + * Adds the AdjustmentListener to current Adjustment. + * + * @param a0 + * the AdjustmentListener object. + */ + public void addAdjustmentListener(AdjustmentListener a0); + + /** + * Gets the block increment of the Adjustable. + * + * @return the block increment of the Adjustable. + */ + public int getBlockIncrement(); + + /** + * Gets the maximum value of the Adjustable. + * + * @return the maximum value of the Adjustable. + */ + public int getMaximum(); + + /** + * Gets the minimum value of the Adjustable. + * + * @return the minimum value of the Adjustable. + */ + public int getMinimum(); + + /** + * Gets the orientation of the Adjustable. + * + * @return the orientation of the Adjustable. + */ + public int getOrientation(); + + /** + * Gets the unit increment of the Adjustable. + * + * @return the unit increment of the Adjustable. + */ + public int getUnitIncrement(); + + /** + * Gets the visible amount of the Adjustable. + * + * @return the visible amount of the Adjustable. + */ + public int getVisibleAmount(); + + /** + * Removes the adjustment listener of the Adjustable. + * + * @param a0 + * the specified AdjustmentListener to be removed. + */ + public void removeAdjustmentListener(AdjustmentListener a0); + + /** + * Sets the block increment for the Adjustable. + * + * @param a0 + * the new block increment. + */ + public void setBlockIncrement(int a0); + + /** + * Sets the maximum value of the Adjustable. + * + * @param a0 + * the new maximum of the Adjustable. + */ + public void setMaximum(int a0); + + /** + * Sets the minimum value of the Adjustable. + * + * @param a0 + * the new minimum of the Adjustable. + */ + public void setMinimum(int a0); + + /** + * Sets the unit increment of the Adjustable. + * + * @param a0 + * the new unit increment of the Adjustable. + */ + public void setUnitIncrement(int a0); + + /** + * Sets the visible amount of the Adjustable. + * + * @param a0 + * the new visible amount of the Adjustable. + */ + public void setVisibleAmount(int a0); + +} diff --git a/app/src/main/java/java/awt/AlphaComposite.java b/app/src/main/java/java/awt/AlphaComposite.java new file mode 100644 index 000000000..8389eb462 --- /dev/null +++ b/app/src/main/java/java/awt/AlphaComposite.java @@ -0,0 +1,352 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt; + +import java.awt.Composite; +import java.awt.CompositeContext; +import java.awt.RenderingHints; +import java.awt.image.ColorModel; + +import org.apache.harmony.awt.gl.ICompositeContext; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The AlphaComposite class defines a basic alpha compositing rules for + * combining source and destination colors to achieve blending and transparency + * effects with graphics and images. + * + * @since Android 1.0 + */ +public final class AlphaComposite implements Composite { + + /** + * The Constant CLEAR indicates that both the color and the alpha of the + * destination are cleared (Porter-Duff Clear rule). + */ + public static final int CLEAR = 1; + + /** + * The Constant SRC indicates that the source is copied to the destination + * (Porter-Duff Source rule). + */ + public static final int SRC = 2; + + /** + * The Constant DST indicates that the destination is left untouched + * (Porter-Duff Destination rule). + */ + public static final int DST = 9; + + /** + * The Constant SRC_OVER indicates that the source is composited over the + * destination (Porter-Duff Source Over Destination rule). + */ + public static final int SRC_OVER = 3; + + /** + * The Constant DST_OVER indicates that The destination is composited over + * the source and the result replaces the destination (Porter-Duff + * Destination Over Source rule). + */ + public static final int DST_OVER = 4; + + /** + * The Constant SRC_IN indicates that the part of the source lying inside of + * the destination replaces the destination (Porter-Duff Source In + * Destination rule). + */ + public static final int SRC_IN = 5; + + /** + * The Constant DST_IN indicates that the part of the destination lying + * inside of the source replaces the destination (Porter-Duff Destination In + * Source rule). + */ + public static final int DST_IN = 6; + + /** + * The Constant SRC_OUT indicates that the part of the source lying outside + * of the destination replaces the destination (Porter-Duff Source Held Out + * By Destination rule). + */ + public static final int SRC_OUT = 7; + + /** + * The Constant DST_OUT indicates that the part of the destination lying + * outside of the source replaces the destination (Porter-Duff Destination + * Held Out By Source rule). + */ + public static final int DST_OUT = 8; + + /** + * The Constant SRC_ATOP indicates that the part of the source lying inside + * of the destination is composited onto the destination (Porter-Duff Source + * Atop Destination rule). + */ + public static final int SRC_ATOP = 10; + + /** + * The Constant DST_ATOP indicates that the part of the destination lying + * inside of the source is composited over the source and replaces the + * destination (Porter-Duff Destination Atop Source rule). + */ + public static final int DST_ATOP = 11; + + /** + * The Constant XOR indicates that the part of the source that lies outside + * of the destination is combined with the part of the destination that lies + * outside of the source (Porter-Duff Source Xor Destination rule). + */ + public static final int XOR = 12; + + /** + * AlphaComposite object with the opaque CLEAR rule and an alpha of 1.0f. + */ + public static final AlphaComposite Clear = new AlphaComposite(CLEAR); + + /** + * AlphaComposite object with the opaque SRC rule and an alpha of 1.0f. + */ + public static final AlphaComposite Src = new AlphaComposite(SRC); + + /** + * AlphaComposite object with the opaque DST rule and an alpha of 1.0f. + */ + public static final AlphaComposite Dst = new AlphaComposite(DST); + + /** + * AlphaComposite object with the opaque SRC_OVER rule and an alpha of 1.0f. + */ + public static final AlphaComposite SrcOver = new AlphaComposite(SRC_OVER); + + /** + * AlphaComposite object with the opaque DST_OVER rule and an alpha of 1.0f. + */ + public static final AlphaComposite DstOver = new AlphaComposite(DST_OVER); + + /** + * AlphaComposite object with the opaque SRC_IN rule and an alpha of 1.0f. + */ + public static final AlphaComposite SrcIn = new AlphaComposite(SRC_IN); + + /** + * AlphaComposite object with the opaque DST_IN rule and an alpha of 1.0f. + */ + public static final AlphaComposite DstIn = new AlphaComposite(DST_IN); + + /** + * AlphaComposite object with the opaque SRC_OUT rule and an alpha of 1.0f. + */ + public static final AlphaComposite SrcOut = new AlphaComposite(SRC_OUT); + + /** + * AlphaComposite object with the opaque DST_OUT rule and an alpha of 1.0f. + */ + public static final AlphaComposite DstOut = new AlphaComposite(DST_OUT); + + /** + * AlphaComposite object with the opaque SRC_ATOP rule and an alpha of 1.0f. + */ + public static final AlphaComposite SrcAtop = new AlphaComposite(SRC_ATOP); + + /** + * AlphaComposite object with the opaque DST_ATOP rule and an alpha of 1.0f. + */ + public static final AlphaComposite DstAtop = new AlphaComposite(DST_ATOP); + + /** + * AlphaComposite object with the opaque XOR rule and an alpha of 1.0f. + */ + public static final AlphaComposite Xor = new AlphaComposite(XOR); + + /** + * The rule. + */ + private int rule; + + /** + * The alpha. + */ + private float alpha; + + /** + * Instantiates a new alpha composite. Creates a context for the compositing + * operation. The context contains state that is used in performing the + * compositing operation. + * + * @param rule + * the rule. + * @param alpha + * the alpha. + */ + private AlphaComposite(int rule, float alpha) { + if (rule < CLEAR || rule > XOR) { + // awt.11D=Unknown rule + throw new IllegalArgumentException(Messages.getString("awt.11D")); //$NON-NLS-1$ + } + if (alpha < 0.0f || alpha > 1.0f) { + // awt.11E=Wrong alpha value + throw new IllegalArgumentException(Messages.getString("awt.11E")); //$NON-NLS-1$ + } + + this.rule = rule; + this.alpha = alpha; + } + + /** + * Instantiates a new alpha composite. + * + * @param rule + * the rule. + */ + private AlphaComposite(int rule) { + this(rule, 1.0f); + } + + /** + * Creates a CompositeContext object with the specified source ColorModel, + * destination ColorModel and RenderingHints parameters for a composing + * operation. + * + * @param srcColorModel + * the source's ColorModel. + * @param dstColorModel + * the destination's ColorModel. + * @param hints + * the RenderingHints object. + * @return the CompositeContext object. + * @see java.awt.Composite#createContext(java.awt.image.ColorModel, + * java.awt.image.ColorModel, java.awt.RenderingHints) + */ + public CompositeContext createContext(ColorModel srcColorModel, ColorModel dstColorModel, + RenderingHints hints) { + return new ICompositeContext(this, srcColorModel, dstColorModel); + } + + /** + * Compares the AlphaComposite object with the specified object. + * + * @param obj + * the Object to be compared. + * @return true, if the AlphaComposite object is equal to the specified + * object. + */ + @Override + public boolean equals(Object obj) { + if (!(obj instanceof AlphaComposite)) { + return false; + } + AlphaComposite other = (AlphaComposite)obj; + return (this.rule == other.getRule() && this.alpha == other.getAlpha()); + } + + /** + * Returns the hash code of the AlphaComposite object. + * + * @return the hash code of the AlphaComposite object. + */ + @Override + public int hashCode() { + int hash = Float.floatToIntBits(alpha); + int tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= rule; + return hash; + } + + /** + * Gets the compositing rule of this AlphaComposite object. + * + * @return the compositing rule of this AlphaComposite object. + */ + public int getRule() { + return rule; + } + + /** + * Gets the alpha value of this AlphaComposite object; returns 1.0 if this + * AlphaComposite object doesn't have alpha value. + * + * @return the alpha value of this AlphaComposite object or 1.0 if this + * AlphaComposite object doesn't have alpha value. + */ + public float getAlpha() { + return alpha; + } + + /** + * Gets the AlphaComposite instance with the specified rule and alpha value. + * + * @param rule + * the compositing rule. + * @param alpha + * the alpha value. + * @return the AlphaComposite instance. + */ + public static AlphaComposite getInstance(int rule, float alpha) { + if (alpha == 1.0f) { + return getInstance(rule); + } + return new AlphaComposite(rule, alpha); + } + + /** + * Gets the AlphaComposite instance with the specified rule. + * + * @param rule + * the compositing rule. + * @return the AlphaComposite instance. + */ + public static AlphaComposite getInstance(int rule) { + switch (rule) { + case CLEAR: + return Clear; + case SRC: + return Src; + case DST: + return Dst; + case SRC_OVER: + return SrcOver; + case DST_OVER: + return DstOver; + case SRC_IN: + return SrcIn; + case DST_IN: + return DstIn; + case SRC_OUT: + return SrcOut; + case DST_OUT: + return DstOut; + case SRC_ATOP: + return SrcAtop; + case DST_ATOP: + return DstAtop; + case XOR: + return Xor; + default: + // awt.11D=Unknown rule + throw new IllegalArgumentException(Messages.getString("awt.11D")); //$NON-NLS-1$ + } + } + +} diff --git a/app/src/main/java/java/awt/BasicStroke.java b/app/src/main/java/java/awt/BasicStroke.java new file mode 100644 index 000000000..6a8b04e2c --- /dev/null +++ b/app/src/main/java/java/awt/BasicStroke.java @@ -0,0 +1,2443 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Denis M. Kishenko + * @version $Revision$ + */ + +package java.awt; + +import java.awt.geom.GeneralPath; +import java.awt.geom.PathIterator; + +import org.apache.harmony.awt.internal.nls.Messages; +import org.apache.harmony.misc.HashCode; + +/** + * The BasicStroke class specifies a set of rendering attributes for the + * outlines of graphics primitives. The BasicStroke attributes describe the + * shape of the pen which draws the outline of a Shape and the decorations + * applied at the ends and joins of path segments of the Shape. The BasicStroke + * has the following rendering attributes: + *

+ *

    + *
  • line width -the pen width which draws the outlines.
  • + *
  • end caps - indicates the decoration applied to the ends of unclosed + * subpaths and dash segments. The BasicStroke defines three different + * decorations: CAP_BUTT, CAP_ROUND, and CAP_SQUARE.
  • + *
  • line joins - indicates the decoration applied at the intersection of two + * path segments and at the intersection of the endpoints of a subpath. The + * BasicStroke defines three decorations: JOIN_BEVEL, JOIN_MITER, and + * JOIN_ROUND.
  • + *
  • miter limit - the limit to trim a line join that has a JOIN_MITER + * decoration.
  • + *
  • dash attributes - the definition of how to make a dash pattern by + * alternating between opaque and transparent sections
  • + *
+ *

+ * + * @since Android 1.0 + */ +public class BasicStroke implements Stroke { + + /** + * The Constant CAP_BUTT indicates the ends of unclosed subpaths and dash + * segments have no added decoration. + */ + public static final int CAP_BUTT = 0; + + /** + * The Constant CAP_ROUND indicates the ends of unclosed subpaths and dash + * segments have a round decoration. + */ + public static final int CAP_ROUND = 1; + + /** + * The Constant CAP_SQUARE indicates the ends of unclosed subpaths and dash + * segments have a square projection. + */ + public static final int CAP_SQUARE = 2; + + /** + * The Constant JOIN_MITER indicates that path segments are joined by + * extending their outside edges until they meet. + */ + public static final int JOIN_MITER = 0; + + /** + * The Constant JOIN_ROUND indicates that path segments are joined by + * rounding off the corner at a radius of half the line width. + */ + public static final int JOIN_ROUND = 1; + + /** + * The Constant JOIN_BEVEL indicates that path segments are joined by + * connecting the outer corners of their wide outlines with a straight + * segment. + */ + public static final int JOIN_BEVEL = 2; + + /** + * Constants for calculating. + */ + static final int MAX_LEVEL = 20; // Maximal deepness of curve subdivision + + /** + * The Constant CURVE_DELTA. + */ + static final double CURVE_DELTA = 2.0; // Width tolerance + + /** + * The Constant CORNER_ANGLE. + */ + static final double CORNER_ANGLE = 4.0; // Minimum corner angle + + /** + * The Constant CORNER_ZERO. + */ + static final double CORNER_ZERO = 0.01; // Zero angle + + /** + * The Constant CUBIC_ARC. + */ + static final double CUBIC_ARC = 4.0 / 3.0 * (Math.sqrt(2.0) - 1); + + /** + * Stroke width. + */ + float width; + + /** + * Stroke cap type. + */ + int cap; + + /** + * Stroke join type. + */ + int join; + + /** + * Stroke miter limit. + */ + float miterLimit; + + /** + * Stroke dashes array. + */ + float dash[]; + + /** + * Stroke dash phase. + */ + float dashPhase; + + /** + * The temporary pre-calculated values. + */ + double curveDelta; + + /** + * The corner delta. + */ + double cornerDelta; + + /** + * The zero delta. + */ + double zeroDelta; + + /** + * The w2. + */ + double w2; + + /** + * The fmy. + */ + double fmx, fmy; + + /** + * The smy. + */ + double scx, scy, smx, smy; + + /** + * The cy. + */ + double mx, my, cx, cy; + + /** + * The temporary indicators. + */ + boolean isMove; + + /** + * The is first. + */ + boolean isFirst; + + /** + * The check move. + */ + boolean checkMove; + + /** + * The temporary and destination work paths. + */ + BufferedPath dst, lp, rp, sp; + + /** + * Stroke dasher class. + */ + Dasher dasher; + + /** + * Instantiates a new BasicStroke with default width, cap, join, limit, dash + * attributes parameters. The default parameters are a solid line of width + * 1.0, CAP_SQUARE, JOIN_MITER, a miter limit of 10.0, null dash attributes, + * and a dash phase of 0.0f. + */ + public BasicStroke() { + this(1.0f, CAP_SQUARE, JOIN_MITER, 10.0f, null, 0.0f); + } + + /** + * Instantiates a new BasicStroke with the specified width, caps, joins, + * limit, dash attributes, dash phase parameters. + * + * @param width + * the width of BasikStroke. + * @param cap + * the end decoration of BasikStroke. + * @param join + * the join segments decoration. + * @param miterLimit + * the limit to trim the miter join. + * @param dash + * the array with the dashing pattern. + * @param dashPhase + * the offset to start the dashing pattern. + */ + public BasicStroke(float width, int cap, int join, float miterLimit, float[] dash, + float dashPhase) { + if (width < 0.0f) { + // awt.133=Negative width + throw new IllegalArgumentException(Messages.getString("awt.133")); //$NON-NLS-1$ + } + if (cap != CAP_BUTT && cap != CAP_ROUND && cap != CAP_SQUARE) { + // awt.134=Illegal cap + throw new IllegalArgumentException(Messages.getString("awt.134")); //$NON-NLS-1$ + } + if (join != JOIN_MITER && join != JOIN_ROUND && join != JOIN_BEVEL) { + // awt.135=Illegal join + throw new IllegalArgumentException(Messages.getString("awt.135")); //$NON-NLS-1$ + } + if (join == JOIN_MITER && miterLimit < 1.0f) { + // awt.136=miterLimit less than 1.0f + throw new IllegalArgumentException(Messages.getString("awt.136")); //$NON-NLS-1$ + } + if (dash != null) { + if (dashPhase < 0.0f) { + // awt.137=Negative dashPhase + throw new IllegalArgumentException(Messages.getString("awt.137")); //$NON-NLS-1$ + } + if (dash.length == 0) { + // awt.138=Zero dash length + throw new IllegalArgumentException(Messages.getString("awt.138")); //$NON-NLS-1$ + } + ZERO: { + for (int i = 0; i < dash.length; i++) { + if (dash[i] < 0.0) { + // awt.139=Negative dash[{0}] + throw new IllegalArgumentException(Messages.getString("awt.139", i)); //$NON-NLS-1$ + } + if (dash[i] > 0.0) { + break ZERO; + } + } + // awt.13A=All dash lengths zero + throw new IllegalArgumentException(Messages.getString("awt.13A")); //$NON-NLS-1$ + } + } + this.width = width; + this.cap = cap; + this.join = join; + this.miterLimit = miterLimit; + this.dash = dash; + this.dashPhase = dashPhase; + } + + /** + * Instantiates a new BasicStroke with specified width, cap, join, limit and + * default dash attributes parameters. + * + * @param width + * the width of BasikStroke. + * @param cap + * the end decoration of BasikStroke. + * @param join + * the join segments decoration. + * @param miterLimit + * the limit to trim the miter join. + */ + public BasicStroke(float width, int cap, int join, float miterLimit) { + this(width, cap, join, miterLimit, null, 0.0f); + } + + /** + * Instantiates a new BasicStroke with specified width, cap, join and + * default limit and dash attributes parameters. + * + * @param width + * the width of BasikStroke. + * @param cap + * the end decoration of BasikStroke. + * @param join + * the join segments decoration. + */ + public BasicStroke(float width, int cap, int join) { + this(width, cap, join, 10.0f, null, 0.0f); + } + + /** + * Instantiates a new BasicStroke with specified width and default cap, + * join, limit, dash attributes parameters. + * + * @param width + * the width of BasicStroke. + */ + public BasicStroke(float width) { + this(width, CAP_SQUARE, JOIN_MITER, 10.0f, null, 0.0f); + } + + /** + * Gets the line width of the BasicStroke. + * + * @return the line width of the BasicStroke. + */ + public float getLineWidth() { + return width; + } + + /** + * Gets the end cap style of the BasicStroke. + * + * @return the end cap style of the BasicStroke. + */ + public int getEndCap() { + return cap; + } + + /** + * Gets the line join style of the BasicStroke. + * + * @return the line join style of the BasicStroke. + */ + public int getLineJoin() { + return join; + } + + /** + * Gets the miter limit of the BasicStroke (the limit to trim the miter + * join). + * + * @return the miter limit of the BasicStroke. + */ + public float getMiterLimit() { + return miterLimit; + } + + /** + * Gets the dash attributes array of the BasicStroke. + * + * @return the dash attributes array of the BasicStroke. + */ + public float[] getDashArray() { + return dash; + } + + /** + * Gets the dash phase of the BasicStroke. + * + * @return the dash phase of the BasicStroke. + */ + public float getDashPhase() { + return dashPhase; + } + + /** + * Returns hash code of this BasicStroke. + * + * @return the hash code of this BasicStroke. + */ + @Override + public int hashCode() { + HashCode hash = new HashCode(); + hash.append(width); + hash.append(cap); + hash.append(join); + hash.append(miterLimit); + if (dash != null) { + hash.append(dashPhase); + for (float element : dash) { + hash.append(element); + } + } + return hash.hashCode(); + } + + /** + * Compares this BasicStroke object with the specified Object. + * + * @param obj + * the Object to be compared. + * @return true, if the Object is a BasicStroke with the same data values as + * this BasicStroke; false otherwise. + */ + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof BasicStroke) { + BasicStroke bs = (BasicStroke)obj; + return bs.width == width && bs.cap == cap && bs.join == join + && bs.miterLimit == miterLimit && bs.dashPhase == dashPhase + && java.util.Arrays.equals(bs.dash, dash); + } + return false; + } + + /** + * Calculates allowable curve derivation. + * + * @param width + * the width. + * @return the curve delta. + */ + double getCurveDelta(double width) { + double a = width + CURVE_DELTA; + double cos = 1.0 - 2.0 * width * width / (a * a); + double sin = Math.sqrt(1.0 - cos * cos); + return Math.abs(sin / cos); + } + + /** + * Calculates the value to detect a small angle. + * + * @param width + * the width. + * @return the corner delta. + */ + double getCornerDelta(double width) { + return width * width * Math.sin(Math.PI * CORNER_ANGLE / 180.0); + } + + /** + * Calculates value to detect a zero angle. + * + * @param width + * the width. + * @return the zero delta. + */ + double getZeroDelta(double width) { + return width * width * Math.sin(Math.PI * CORNER_ZERO / 180.0); + } + + /** + * Creates a Shape from the outline of the specified shape drawn with this + * BasicStroke. + * + * @param s + * the specified Shape to be stroked. + * @return the Shape of the stroked outline. + * @see java.awt.Stroke#createStrokedShape(java.awt.Shape) + */ + public Shape createStrokedShape(Shape s) { + w2 = width / 2.0; + curveDelta = getCurveDelta(w2); + cornerDelta = getCornerDelta(w2); + zeroDelta = getZeroDelta(w2); + + dst = new BufferedPath(); + lp = new BufferedPath(); + rp = new BufferedPath(); + + if (dash == null) { + createSolidShape(s.getPathIterator(null)); + } else { + createDashedShape(s.getPathIterator(null)); + } + + return dst.createGeneralPath(); + } + + /** + * Generates a shape with a solid (not dashed) outline. + * + * @param p + * the PathIterator of source shape. + */ + void createSolidShape(PathIterator p) { + double coords[] = new double[6]; + mx = my = cx = cy = 0.0; + isMove = false; + isFirst = false; + checkMove = true; + boolean isClosed = true; + + while (!p.isDone()) { + switch (p.currentSegment(coords)) { + case PathIterator.SEG_MOVETO: + if (!isClosed) { + closeSolidShape(); + } + rp.clean(); + mx = cx = coords[0]; + my = cy = coords[1]; + isMove = true; + isClosed = false; + break; + case PathIterator.SEG_LINETO: + addLine(cx, cy, cx = coords[0], cy = coords[1], true); + break; + case PathIterator.SEG_QUADTO: + addQuad(cx, cy, coords[0], coords[1], cx = coords[2], cy = coords[3]); + break; + case PathIterator.SEG_CUBICTO: + addCubic(cx, cy, coords[0], coords[1], coords[2], coords[3], cx = coords[4], + cy = coords[5]); + break; + case PathIterator.SEG_CLOSE: + addLine(cx, cy, mx, my, false); + addJoin(lp, mx, my, lp.xMove, lp.yMove, true); + addJoin(rp, mx, my, rp.xMove, rp.yMove, false); + lp.closePath(); + rp.closePath(); + lp.appendReverse(rp); + isClosed = true; + break; + } + p.next(); + } + if (!isClosed) { + closeSolidShape(); + } + + dst = lp; + } + + /** + * Closes solid shape path. + */ + void closeSolidShape() { + addCap(lp, cx, cy, rp.xLast, rp.yLast); + lp.combine(rp); + addCap(lp, mx, my, lp.xMove, lp.yMove); + lp.closePath(); + } + + /** + * Generates dashed stroked shape. + * + * @param p + * the PathIterator of source shape. + */ + void createDashedShape(PathIterator p) { + double coords[] = new double[6]; + mx = my = cx = cy = 0.0; + smx = smy = scx = scy = 0.0; + isMove = false; + checkMove = false; + boolean isClosed = true; + + while (!p.isDone()) { + switch (p.currentSegment(coords)) { + case PathIterator.SEG_MOVETO: + + if (!isClosed) { + closeDashedShape(); + } + + dasher = new Dasher(dash, dashPhase); + lp.clean(); + rp.clean(); + sp = null; + isFirst = true; + isMove = true; + isClosed = false; + mx = cx = coords[0]; + my = cy = coords[1]; + break; + case PathIterator.SEG_LINETO: + addDashLine(cx, cy, cx = coords[0], cy = coords[1]); + break; + case PathIterator.SEG_QUADTO: + addDashQuad(cx, cy, coords[0], coords[1], cx = coords[2], cy = coords[3]); + break; + case PathIterator.SEG_CUBICTO: + addDashCubic(cx, cy, coords[0], coords[1], coords[2], coords[3], + cx = coords[4], cy = coords[5]); + break; + case PathIterator.SEG_CLOSE: + addDashLine(cx, cy, cx = mx, cy = my); + + if (dasher.isConnected()) { + // Connect current and head segments + addJoin(lp, fmx, fmy, sp.xMove, sp.yMove, true); + lp.join(sp); + addJoin(lp, fmx, fmy, rp.xLast, rp.yLast, true); + lp.combine(rp); + addCap(lp, smx, smy, lp.xMove, lp.yMove); + lp.closePath(); + dst.append(lp); + sp = null; + } else { + closeDashedShape(); + } + + isClosed = true; + break; + } + p.next(); + } + + if (!isClosed) { + closeDashedShape(); + } + + } + + /** + * Closes dashed shape path. + */ + void closeDashedShape() { + // Add head segment + if (sp != null) { + addCap(sp, fmx, fmy, sp.xMove, sp.yMove); + sp.closePath(); + dst.append(sp); + } + if (lp.typeSize > 0) { + // Close current segment + if (!dasher.isClosed()) { + addCap(lp, scx, scy, rp.xLast, rp.yLast); + lp.combine(rp); + addCap(lp, smx, smy, lp.xMove, lp.yMove); + lp.closePath(); + } + dst.append(lp); + } + } + + /** + * Adds cap to the work path. + * + * @param p + * the BufferedPath object of work path. + * @param x0 + * the x coordinate of the source path. + * @param y0 + * the y coordinate on the source path. + * @param x2 + * the x coordinate of the next point on the work path. + * @param y2 + * the y coordinate of the next point on the work path. + */ + void addCap(BufferedPath p, double x0, double y0, double x2, double y2) { + double x1 = p.xLast; + double y1 = p.yLast; + double x10 = x1 - x0; + double y10 = y1 - y0; + double x20 = x2 - x0; + double y20 = y2 - y0; + + switch (cap) { + case CAP_BUTT: + p.lineTo(x2, y2); + break; + case CAP_ROUND: + double mx = x10 * CUBIC_ARC; + double my = y10 * CUBIC_ARC; + + double x3 = x0 + y10; + double y3 = y0 - x10; + + x10 *= CUBIC_ARC; + y10 *= CUBIC_ARC; + x20 *= CUBIC_ARC; + y20 *= CUBIC_ARC; + + p.cubicTo(x1 + y10, y1 - x10, x3 + mx, y3 + my, x3, y3); + p.cubicTo(x3 - mx, y3 - my, x2 - y20, y2 + x20, x2, y2); + break; + case CAP_SQUARE: + p.lineTo(x1 + y10, y1 - x10); + p.lineTo(x2 - y20, y2 + x20); + p.lineTo(x2, y2); + break; + } + } + + /** + * Adds bevel and miter join to the work path. + * + * @param p + * the BufferedPath object of work path. + * @param x0 + * the x coordinate of the source path. + * @param y0 + * the y coordinate on the source path. + * @param x2 + * the x coordinate of the next point on the work path. + * @param y2 + * the y coordinate of the next point on the work path. + * @param isLeft + * the orientation of work path, true if work path lies to the + * left from source path, false otherwise. + */ + void addJoin(BufferedPath p, double x0, double y0, double x2, double y2, boolean isLeft) { + double x1 = p.xLast; + double y1 = p.yLast; + double x10 = x1 - x0; + double y10 = y1 - y0; + double x20 = x2 - x0; + double y20 = y2 - y0; + double sin0 = x10 * y20 - y10 * x20; + + // Small corner + if (-cornerDelta < sin0 && sin0 < cornerDelta) { + double cos0 = x10 * x20 + y10 * y20; + if (cos0 > 0.0) { + // if zero corner do nothing + if (-zeroDelta > sin0 || sin0 > zeroDelta) { + double x3 = x0 + w2 * w2 * (y20 - y10) / sin0; + double y3 = y0 + w2 * w2 * (x10 - x20) / sin0; + p.setLast(x3, y3); + } + return; + } + // Zero corner + if (-zeroDelta < sin0 && sin0 < zeroDelta) { + p.lineTo(x2, y2); + } + return; + } + + if (isLeft ^ (sin0 < 0.0)) { + // Twisted corner + p.lineTo(x0, y0); + p.lineTo(x2, y2); + } else { + switch (join) { + case JOIN_BEVEL: + p.lineTo(x2, y2); + break; + case JOIN_MITER: + double s1 = x1 * x10 + y1 * y10; + double s2 = x2 * x20 + y2 * y20; + double x3 = (s1 * y20 - s2 * y10) / sin0; + double y3 = (s2 * x10 - s1 * x20) / sin0; + double x30 = x3 - x0; + double y30 = y3 - y0; + double miterLength = Math.sqrt(x30 * x30 + y30 * y30); + if (miterLength < miterLimit * w2) { + p.lineTo(x3, y3); + } + p.lineTo(x2, y2); + break; + case JOIN_ROUND: + addRoundJoin(p, x0, y0, x2, y2, isLeft); + break; + } + } + } + + /** + * Adds round join to the work path. + * + * @param p + * the BufferedPath object of work path. + * @param x0 + * the x coordinate of the source path. + * @param y0 + * the y coordinate on the source path. + * @param x2 + * the x coordinate of the next point on the work path. + * @param y2 + * the y coordinate of the next point on the work path. + * @param isLeft + * the orientation of work path, true if work path lies to the + * left from source path, false otherwise. + */ + void addRoundJoin(BufferedPath p, double x0, double y0, double x2, double y2, boolean isLeft) { + double x1 = p.xLast; + double y1 = p.yLast; + double x10 = x1 - x0; + double y10 = y1 - y0; + double x20 = x2 - x0; + double y20 = y2 - y0; + + double x30 = x10 + x20; + double y30 = y10 + y20; + + double l30 = Math.sqrt(x30 * x30 + y30 * y30); + + if (l30 < 1E-5) { + p.lineTo(x2, y2); + return; + } + + double w = w2 / l30; + + x30 *= w; + y30 *= w; + + double x3 = x0 + x30; + double y3 = y0 + y30; + + double cos = x10 * x20 + y10 * y20; + double a = Math.acos(cos / (w2 * w2)); + if (cos >= 0.0) { + double k = 4.0 / 3.0 * Math.tan(a / 4.0); + if (isLeft) { + k = -k; + } + + x10 *= k; + y10 *= k; + x20 *= k; + y20 *= k; + + p.cubicTo(x1 - y10, y1 + x10, x2 + y20, y2 - x20, x2, y2); + } else { + double k = 4.0 / 3.0 * Math.tan(a / 8.0); + if (isLeft) { + k = -k; + } + + x10 *= k; + y10 *= k; + x20 *= k; + y20 *= k; + x30 *= k; + y30 *= k; + + p.cubicTo(x1 - y10, y1 + x10, x3 + y30, y3 - x30, x3, y3); + p.cubicTo(x3 - y30, y3 + x30, x2 + y20, y2 - x20, x2, y2); + } + + } + + /** + * Adds solid line segment to the work path. + * + * @param x1 + * the x coordinate of the start line point. + * @param y1 + * the y coordinate of the start line point. + * @param x2 + * the x coordinate of the end line point. + * @param y2 + * the y coordinate of the end line point. + * @param zero + * if true it's allowable to add zero length line segment. + */ + void addLine(double x1, double y1, double x2, double y2, boolean zero) { + double dx = x2 - x1; + double dy = y2 - y1; + + if (dx == 0.0 && dy == 0.0) { + if (!zero) { + return; + } + dx = w2; + dy = 0; + } else { + double w = w2 / Math.sqrt(dx * dx + dy * dy); + dx *= w; + dy *= w; + } + + double lx1 = x1 - dy; + double ly1 = y1 + dx; + double rx1 = x1 + dy; + double ry1 = y1 - dx; + + if (checkMove) { + if (isMove) { + isMove = false; + lp.moveTo(lx1, ly1); + rp.moveTo(rx1, ry1); + } else { + addJoin(lp, x1, y1, lx1, ly1, true); + addJoin(rp, x1, y1, rx1, ry1, false); + } + } + + lp.lineTo(x2 - dy, y2 + dx); + rp.lineTo(x2 + dy, y2 - dx); + } + + /** + * Adds solid quad segment to the work path. + * + * @param x1 + * the x coordinate of the first control point. + * @param y1 + * the y coordinate of the first control point. + * @param x2 + * the x coordinate of the second control point. + * @param y2 + * the y coordinate of the second control point. + * @param x3 + * the x coordinate of the third control point. + * @param y3 + * the y coordinate of the third control point. + */ + void addQuad(double x1, double y1, double x2, double y2, double x3, double y3) { + double x21 = x2 - x1; + double y21 = y2 - y1; + double x23 = x2 - x3; + double y23 = y2 - y3; + + double l21 = Math.sqrt(x21 * x21 + y21 * y21); + double l23 = Math.sqrt(x23 * x23 + y23 * y23); + + if (l21 == 0.0 && l23 == 0.0) { + addLine(x1, y1, x3, y3, false); + return; + } + + if (l21 == 0.0) { + addLine(x2, y2, x3, y3, false); + return; + } + + if (l23 == 0.0) { + addLine(x1, y1, x2, y2, false); + return; + } + + double w; + w = w2 / l21; + double mx1 = -y21 * w; + double my1 = x21 * w; + w = w2 / l23; + double mx3 = y23 * w; + double my3 = -x23 * w; + + double lx1 = x1 + mx1; + double ly1 = y1 + my1; + double rx1 = x1 - mx1; + double ry1 = y1 - my1; + + if (checkMove) { + if (isMove) { + isMove = false; + lp.moveTo(lx1, ly1); + rp.moveTo(rx1, ry1); + } else { + addJoin(lp, x1, y1, lx1, ly1, true); + addJoin(rp, x1, y1, rx1, ry1, false); + } + } + + if (x21 * y23 - y21 * x23 == 0.0) { + // On line curve + if (x21 * x23 + y21 * y23 > 0.0) { + // Twisted curve + if (l21 == l23) { + double px = x1 + (x21 + x23) / 4.0; + double py = y1 + (y21 + y23) / 4.0; + lp.lineTo(px + mx1, py + my1); + rp.lineTo(px - mx1, py - my1); + lp.lineTo(px - mx1, py - my1); + rp.lineTo(px + mx1, py + my1); + lp.lineTo(x3 - mx1, y3 - my1); + rp.lineTo(x3 + mx1, y3 + my1); + } else { + double px1, py1; + double k = l21 / (l21 + l23); + double px = x1 + (x21 + x23) * k * k; + double py = y1 + (y21 + y23) * k * k; + px1 = (x1 + px) / 2.0; + py1 = (y1 + py) / 2.0; + lp.quadTo(px1 + mx1, py1 + my1, px + mx1, py + my1); + rp.quadTo(px1 - mx1, py1 - my1, px - mx1, py - my1); + lp.lineTo(px - mx1, py - my1); + rp.lineTo(px + mx1, py + my1); + px1 = (x3 + px) / 2.0; + py1 = (y3 + py) / 2.0; + lp.quadTo(px1 - mx1, py1 - my1, x3 - mx1, y3 - my1); + rp.quadTo(px1 + mx1, py1 + my1, x3 + mx1, y3 + my1); + } + } else { + // Simple curve + lp.quadTo(x2 + mx1, y2 + my1, x3 + mx3, y3 + my3); + rp.quadTo(x2 - mx1, y2 - my1, x3 - mx3, y3 - my3); + } + } else { + addSubQuad(x1, y1, x2, y2, x3, y3, 0); + } + } + + /** + * Subdivides solid quad curve to make outline for source quad segment and + * adds it to work path. + * + * @param x1 + * the x coordinate of the first control point. + * @param y1 + * the y coordinate of the first control point. + * @param x2 + * the x coordinate of the second control point. + * @param y2 + * the y coordinate of the second control point. + * @param x3 + * the x coordinate of the third control point. + * @param y3 + * the y coordinate of the third control point. + * @param level + * the maximum level of subdivision deepness. + */ + void addSubQuad(double x1, double y1, double x2, double y2, double x3, double y3, int level) { + double x21 = x2 - x1; + double y21 = y2 - y1; + double x23 = x2 - x3; + double y23 = y2 - y3; + + double cos = x21 * x23 + y21 * y23; + double sin = x21 * y23 - y21 * x23; + + if (level < MAX_LEVEL && (cos >= 0.0 || (Math.abs(sin / cos) > curveDelta))) { + double c1x = (x2 + x1) / 2.0; + double c1y = (y2 + y1) / 2.0; + double c2x = (x2 + x3) / 2.0; + double c2y = (y2 + y3) / 2.0; + double c3x = (c1x + c2x) / 2.0; + double c3y = (c1y + c2y) / 2.0; + addSubQuad(x1, y1, c1x, c1y, c3x, c3y, level + 1); + addSubQuad(c3x, c3y, c2x, c2y, x3, y3, level + 1); + } else { + double w; + double l21 = Math.sqrt(x21 * x21 + y21 * y21); + double l23 = Math.sqrt(x23 * x23 + y23 * y23); + w = w2 / sin; + double mx2 = (x21 * l23 + x23 * l21) * w; + double my2 = (y21 * l23 + y23 * l21) * w; + w = w2 / l23; + double mx3 = y23 * w; + double my3 = -x23 * w; + lp.quadTo(x2 + mx2, y2 + my2, x3 + mx3, y3 + my3); + rp.quadTo(x2 - mx2, y2 - my2, x3 - mx3, y3 - my3); + } + } + + /** + * Adds solid cubic segment to the work path. + * + * @param x1 + * the x coordinate of the first control point. + * @param y1 + * the y coordinate of the first control point. + * @param x2 + * the x coordinate of the second control point. + * @param y2 + * the y coordinate of the second control point. + * @param x3 + * the x coordinate of the third control point. + * @param y3 + * the y coordinate of the third control point. + * @param x4 + * the x coordinate of the fours control point. + * @param y4 + * the y coordinate of the fours control point. + */ + void addCubic(double x1, double y1, double x2, double y2, double x3, double y3, double x4, + double y4) { + double x12 = x1 - x2; + double y12 = y1 - y2; + double x23 = x2 - x3; + double y23 = y2 - y3; + double x34 = x3 - x4; + double y34 = y3 - y4; + + double l12 = Math.sqrt(x12 * x12 + y12 * y12); + double l23 = Math.sqrt(x23 * x23 + y23 * y23); + double l34 = Math.sqrt(x34 * x34 + y34 * y34); + + // All edges are zero + if (l12 == 0.0 && l23 == 0.0 && l34 == 0.0) { + addLine(x1, y1, x4, y4, false); + return; + } + + // One zero edge + if (l12 == 0.0 && l23 == 0.0) { + addLine(x3, y3, x4, y4, false); + return; + } + + if (l23 == 0.0 && l34 == 0.0) { + addLine(x1, y1, x2, y2, false); + return; + } + + if (l12 == 0.0 && l34 == 0.0) { + addLine(x2, y2, x3, y3, false); + return; + } + + double w, mx1, my1, mx4, my4; + boolean onLine; + + if (l12 == 0.0) { + w = w2 / l23; + mx1 = y23 * w; + my1 = -x23 * w; + w = w2 / l34; + mx4 = y34 * w; + my4 = -x34 * w; + onLine = -x23 * y34 + y23 * x34 == 0.0; // sin3 + } else if (l34 == 0.0) { + w = w2 / l12; + mx1 = y12 * w; + my1 = -x12 * w; + w = w2 / l23; + mx4 = y23 * w; + my4 = -x23 * w; + onLine = -x12 * y23 + y12 * x23 == 0.0; // sin2 + } else { + w = w2 / l12; + mx1 = y12 * w; + my1 = -x12 * w; + w = w2 / l34; + mx4 = y34 * w; + my4 = -x34 * w; + if (l23 == 0.0) { + onLine = -x12 * y34 + y12 * x34 == 0.0; + } else { + onLine = -x12 * y34 + y12 * x34 == 0.0 && -x12 * y23 + y12 * x23 == 0.0 && // sin2 + -x23 * y34 + y23 * x34 == 0.0; // sin3 + } + } + + double lx1 = x1 + mx1; + double ly1 = y1 + my1; + double rx1 = x1 - mx1; + double ry1 = y1 - my1; + + if (checkMove) { + if (isMove) { + isMove = false; + lp.moveTo(lx1, ly1); + rp.moveTo(rx1, ry1); + } else { + addJoin(lp, x1, y1, lx1, ly1, true); + addJoin(rp, x1, y1, rx1, ry1, false); + } + } + + if (onLine) { + if ((x1 == x2 && y1 < y2) || x1 < x2) { + l12 = -l12; + } + if ((x2 == x3 && y2 < y3) || x2 < x3) { + l23 = -l23; + } + if ((x3 == x4 && y3 < y4) || x3 < x4) { + l34 = -l34; + } + double d = l23 * l23 - l12 * l34; + double roots[] = new double[3]; + int rc = 0; + if (d == 0.0) { + double t = (l12 - l23) / (l12 + l34 - l23 - l23); + if (0.0 < t && t < 1.0) { + roots[rc++] = t; + } + } else if (d > 0.0) { + d = Math.sqrt(d); + double z = l12 + l34 - l23 - l23; + double t; + t = (l12 - l23 + d) / z; + if (0.0 < t && t < 1.0) { + roots[rc++] = t; + } + t = (l12 - l23 - d) / z; + if (0.0 < t && t < 1.0) { + roots[rc++] = t; + } + } + + if (rc > 0) { + // Sort roots + if (rc == 2 && roots[0] > roots[1]) { + double tmp = roots[0]; + roots[0] = roots[1]; + roots[1] = tmp; + } + roots[rc++] = 1.0; + + double ax = -x34 - x12 + x23 + x23; + double ay = -y34 - y12 + y23 + y23; + double bx = 3.0 * (-x23 + x12); + double by = 3.0 * (-y23 + y12); + double cx = 3.0 * (-x12); + double cy = 3.0 * (-y12); + double xPrev = x1; + double yPrev = y1; + for (int i = 0; i < rc; i++) { + double t = roots[i]; + double px = t * (t * (t * ax + bx) + cx) + x1; + double py = t * (t * (t * ay + by) + cy) + y1; + double px1 = (xPrev + px) / 2.0; + double py1 = (yPrev + py) / 2.0; + lp.cubicTo(px1 + mx1, py1 + my1, px1 + mx1, py1 + my1, px + mx1, py + my1); + rp.cubicTo(px1 - mx1, py1 - my1, px1 - mx1, py1 - my1, px - mx1, py - my1); + if (i < rc - 1) { + lp.lineTo(px - mx1, py - my1); + rp.lineTo(px + mx1, py + my1); + } + xPrev = px; + yPrev = py; + mx1 = -mx1; + my1 = -my1; + } + } else { + lp.cubicTo(x2 + mx1, y2 + my1, x3 + mx4, y3 + my4, x4 + mx4, y4 + my4); + rp.cubicTo(x2 - mx1, y2 - my1, x3 - mx4, y3 - my4, x4 - mx4, y4 - my4); + } + } else { + addSubCubic(x1, y1, x2, y2, x3, y3, x4, y4, 0); + } + } + + /** + * Subdivides solid cubic curve to make outline for source quad segment and + * adds it to work path. + * + * @param x1 + * the x coordinate of the first control point. + * @param y1 + * the y coordinate of the first control point. + * @param x2 + * the x coordinate of the second control point. + * @param y2 + * the y coordinate of the second control point. + * @param x3 + * the x coordinate of the third control point. + * @param y3 + * the y coordinate of the third control point. + * @param x4 + * the x coordinate of the fours control point. + * @param y4 + * the y coordinate of the fours control point. + * @param level + * the maximum level of subdivision deepness. + */ + void addSubCubic(double x1, double y1, double x2, double y2, double x3, double y3, double x4, + double y4, int level) { + double x12 = x1 - x2; + double y12 = y1 - y2; + double x23 = x2 - x3; + double y23 = y2 - y3; + double x34 = x3 - x4; + double y34 = y3 - y4; + + double cos2 = -x12 * x23 - y12 * y23; + double cos3 = -x23 * x34 - y23 * y34; + double sin2 = -x12 * y23 + y12 * x23; + double sin3 = -x23 * y34 + y23 * x34; + double sin0 = -x12 * y34 + y12 * x34; + double cos0 = -x12 * x34 - y12 * y34; + + if (level < MAX_LEVEL + && (sin2 != 0.0 || sin3 != 0.0 || sin0 != 0.0) + && (cos2 >= 0.0 || cos3 >= 0.0 || cos0 >= 0.0 + || (Math.abs(sin2 / cos2) > curveDelta) + || (Math.abs(sin3 / cos3) > curveDelta) || (Math.abs(sin0 / cos0) > curveDelta))) { + double cx = (x2 + x3) / 2.0; + double cy = (y2 + y3) / 2.0; + double lx2 = (x2 + x1) / 2.0; + double ly2 = (y2 + y1) / 2.0; + double rx3 = (x3 + x4) / 2.0; + double ry3 = (y3 + y4) / 2.0; + double lx3 = (cx + lx2) / 2.0; + double ly3 = (cy + ly2) / 2.0; + double rx2 = (cx + rx3) / 2.0; + double ry2 = (cy + ry3) / 2.0; + cx = (lx3 + rx2) / 2.0; + cy = (ly3 + ry2) / 2.0; + addSubCubic(x1, y1, lx2, ly2, lx3, ly3, cx, cy, level + 1); + addSubCubic(cx, cy, rx2, ry2, rx3, ry3, x4, y4, level + 1); + } else { + double w, mx1, my1, mx2, my2, mx3, my3, mx4, my4; + double l12 = Math.sqrt(x12 * x12 + y12 * y12); + double l23 = Math.sqrt(x23 * x23 + y23 * y23); + double l34 = Math.sqrt(x34 * x34 + y34 * y34); + + if (l12 == 0.0) { + w = w2 / l23; + mx1 = y23 * w; + my1 = -x23 * w; + w = w2 / l34; + mx4 = y34 * w; + my4 = -x34 * w; + } else if (l34 == 0.0) { + w = w2 / l12; + mx1 = y12 * w; + my1 = -x12 * w; + w = w2 / l23; + mx4 = y23 * w; + my4 = -x23 * w; + } else { + // Common case + w = w2 / l12; + mx1 = y12 * w; + my1 = -x12 * w; + w = w2 / l34; + mx4 = y34 * w; + my4 = -x34 * w; + } + + if (sin2 == 0.0) { + mx2 = mx1; + my2 = my1; + } else { + w = w2 / sin2; + mx2 = -(x12 * l23 - x23 * l12) * w; + my2 = -(y12 * l23 - y23 * l12) * w; + } + if (sin3 == 0.0) { + mx3 = mx4; + my3 = my4; + } else { + w = w2 / sin3; + mx3 = -(x23 * l34 - x34 * l23) * w; + my3 = -(y23 * l34 - y34 * l23) * w; + } + + lp.cubicTo(x2 + mx2, y2 + my2, x3 + mx3, y3 + my3, x4 + mx4, y4 + my4); + rp.cubicTo(x2 - mx2, y2 - my2, x3 - mx3, y3 - my3, x4 - mx4, y4 - my4); + } + } + + /** + * Adds dashed line segment to the work path. + * + * @param x1 + * the x coordinate of the start line point. + * @param y1 + * the y coordinate of the start line point. + * @param x2 + * the x coordinate of the end line point. + * @param y2 + * the y coordinate of the end line point. + */ + void addDashLine(double x1, double y1, double x2, double y2) { + double x21 = x2 - x1; + double y21 = y2 - y1; + + double l21 = Math.sqrt(x21 * x21 + y21 * y21); + + if (l21 == 0.0) { + return; + } + + double px1, py1; + px1 = py1 = 0.0; + double w = w2 / l21; + double mx = -y21 * w; + double my = x21 * w; + + dasher.init(new DashIterator.Line(l21)); + + while (!dasher.eof()) { + double t = dasher.getValue(); + scx = x1 + t * x21; + scy = y1 + t * y21; + + if (dasher.isOpen()) { + px1 = scx; + py1 = scy; + double lx1 = px1 + mx; + double ly1 = py1 + my; + double rx1 = px1 - mx; + double ry1 = py1 - my; + if (isMove) { + isMove = false; + smx = px1; + smy = py1; + rp.clean(); + lp.moveTo(lx1, ly1); + rp.moveTo(rx1, ry1); + } else { + addJoin(lp, x1, y1, lx1, ly1, true); + addJoin(rp, x1, y1, rx1, ry1, false); + } + } else if (dasher.isContinue()) { + double px2 = scx; + double py2 = scy; + lp.lineTo(px2 + mx, py2 + my); + rp.lineTo(px2 - mx, py2 - my); + if (dasher.close) { + addCap(lp, px2, py2, rp.xLast, rp.yLast); + lp.combine(rp); + if (isFirst) { + isFirst = false; + fmx = smx; + fmy = smy; + sp = lp; + lp = new BufferedPath(); + } else { + addCap(lp, smx, smy, lp.xMove, lp.yMove); + lp.closePath(); + } + isMove = true; + } + } + + dasher.next(); + } + } + + /** + * Adds dashed quad segment to the work path. + * + * @param x1 + * the x coordinate of the first control point. + * @param y1 + * the y coordinate of the first control point. + * @param x2 + * the x coordinate of the second control point. + * @param y2 + * the y coordinate of the second control point. + * @param x3 + * the x coordinate of the third control point. + * @param y3 + * the y coordinate of the third control point. + */ + void addDashQuad(double x1, double y1, double x2, double y2, double x3, double y3) { + + double x21 = x2 - x1; + double y21 = y2 - y1; + double x23 = x2 - x3; + double y23 = y2 - y3; + + double l21 = Math.sqrt(x21 * x21 + y21 * y21); + double l23 = Math.sqrt(x23 * x23 + y23 * y23); + + if (l21 == 0.0 && l23 == 0.0) { + return; + } + + if (l21 == 0.0) { + addDashLine(x2, y2, x3, y3); + return; + } + + if (l23 == 0.0) { + addDashLine(x1, y1, x2, y2); + return; + } + + double ax = x1 + x3 - x2 - x2; + double ay = y1 + y3 - y2 - y2; + double bx = x2 - x1; + double by = y2 - y1; + double cx = x1; + double cy = y1; + + double px1, py1, dx1, dy1; + px1 = py1 = dx1 = dy1 = 0.0; + double prev = 0.0; + + dasher.init(new DashIterator.Quad(x1, y1, x2, y2, x3, y3)); + + while (!dasher.eof()) { + double t = dasher.getValue(); + double dx = t * ax + bx; + double dy = t * ay + by; + scx = t * (dx + bx) + cx; // t^2 * ax + 2.0 * t * bx + cx + scy = t * (dy + by) + cy; // t^2 * ay + 2.0 * t * by + cy + if (dasher.isOpen()) { + px1 = scx; + py1 = scy; + dx1 = dx; + dy1 = dy; + double w = w2 / Math.sqrt(dx1 * dx1 + dy1 * dy1); + double mx1 = -dy1 * w; + double my1 = dx1 * w; + double lx1 = px1 + mx1; + double ly1 = py1 + my1; + double rx1 = px1 - mx1; + double ry1 = py1 - my1; + if (isMove) { + isMove = false; + smx = px1; + smy = py1; + rp.clean(); + lp.moveTo(lx1, ly1); + rp.moveTo(rx1, ry1); + } else { + addJoin(lp, x1, y1, lx1, ly1, true); + addJoin(rp, x1, y1, rx1, ry1, false); + } + } else if (dasher.isContinue()) { + double px3 = scx; + double py3 = scy; + double sx = x2 - x23 * prev; + double sy = y2 - y23 * prev; + double t2 = (t - prev) / (1 - prev); + double px2 = px1 + (sx - px1) * t2; + double py2 = py1 + (sy - py1) * t2; + + addQuad(px1, py1, px2, py2, px3, py3); + if (dasher.isClosed()) { + addCap(lp, px3, py3, rp.xLast, rp.yLast); + lp.combine(rp); + if (isFirst) { + isFirst = false; + fmx = smx; + fmy = smy; + sp = lp; + lp = new BufferedPath(); + } else { + addCap(lp, smx, smy, lp.xMove, lp.yMove); + lp.closePath(); + } + isMove = true; + } + } + + prev = t; + dasher.next(); + } + } + + /** + * Adds dashed cubic segment to the work path. + * + * @param x1 + * the x coordinate of the first control point. + * @param y1 + * the y coordinate of the first control point. + * @param x2 + * the x coordinate of the second control point. + * @param y2 + * the y coordinate of the second control point. + * @param x3 + * the x coordinate of the third control point. + * @param y3 + * the y coordinate of the third control point. + * @param x4 + * the x coordinate of the fours control point. + * @param y4 + * the y coordinate of the fours control point. + */ + void addDashCubic(double x1, double y1, double x2, double y2, double x3, double y3, double x4, + double y4) { + + double x12 = x1 - x2; + double y12 = y1 - y2; + double x23 = x2 - x3; + double y23 = y2 - y3; + double x34 = x3 - x4; + double y34 = y3 - y4; + + double l12 = Math.sqrt(x12 * x12 + y12 * y12); + double l23 = Math.sqrt(x23 * x23 + y23 * y23); + double l34 = Math.sqrt(x34 * x34 + y34 * y34); + + // All edges are zero + if (l12 == 0.0 && l23 == 0.0 && l34 == 0.0) { + // NOTHING + return; + } + + // One zero edge + if (l12 == 0.0 && l23 == 0.0) { + addDashLine(x3, y3, x4, y4); + return; + } + + if (l23 == 0.0 && l34 == 0.0) { + addDashLine(x1, y1, x2, y2); + return; + } + + if (l12 == 0.0 && l34 == 0.0) { + addDashLine(x2, y2, x3, y3); + return; + } + + double ax = x4 - x1 + 3.0 * (x2 - x3); + double ay = y4 - y1 + 3.0 * (y2 - y3); + double bx = 3.0 * (x1 + x3 - x2 - x2); + double by = 3.0 * (y1 + y3 - y2 - y2); + double cx = 3.0 * (x2 - x1); + double cy = 3.0 * (y2 - y1); + double dx = x1; + double dy = y1; + + double px1 = 0.0; + double py1 = 0.0; + double prev = 0.0; + + dasher.init(new DashIterator.Cubic(x1, y1, x2, y2, x3, y3, x4, y4)); + + while (!dasher.eof()) { + + double t = dasher.getValue(); + scx = t * (t * (t * ax + bx) + cx) + dx; + scy = t * (t * (t * ay + by) + cy) + dy; + if (dasher.isOpen()) { + px1 = scx; + py1 = scy; + double dx1 = t * (t * (ax + ax + ax) + bx + bx) + cx; + double dy1 = t * (t * (ay + ay + ay) + by + by) + cy; + double w = w2 / Math.sqrt(dx1 * dx1 + dy1 * dy1); + double mx1 = -dy1 * w; + double my1 = dx1 * w; + double lx1 = px1 + mx1; + double ly1 = py1 + my1; + double rx1 = px1 - mx1; + double ry1 = py1 - my1; + if (isMove) { + isMove = false; + smx = px1; + smy = py1; + rp.clean(); + lp.moveTo(lx1, ly1); + rp.moveTo(rx1, ry1); + } else { + addJoin(lp, x1, y1, lx1, ly1, true); + addJoin(rp, x1, y1, rx1, ry1, false); + } + } else if (dasher.isContinue()) { + double sx1 = x2 - x23 * prev; + double sy1 = y2 - y23 * prev; + double sx2 = x3 - x34 * prev; + double sy2 = y3 - y34 * prev; + double sx3 = sx1 + (sx2 - sx1) * prev; + double sy3 = sy1 + (sy2 - sy1) * prev; + double t2 = (t - prev) / (1 - prev); + double sx4 = sx3 + (sx2 - sx3) * t2; + double sy4 = sy3 + (sy2 - sy3) * t2; + + double px4 = scx; + double py4 = scy; + double px2 = px1 + (sx3 - px1) * t2; + double py2 = py1 + (sy3 - py1) * t2; + double px3 = px2 + (sx4 - px2) * t2; + double py3 = py2 + (sy4 - py2) * t2; + + addCubic(px1, py1, px2, py2, px3, py3, px4, py4); + if (dasher.isClosed()) { + addCap(lp, px4, py4, rp.xLast, rp.yLast); + lp.combine(rp); + if (isFirst) { + isFirst = false; + fmx = smx; + fmy = smy; + sp = lp; + lp = new BufferedPath(); + } else { + addCap(lp, smx, smy, lp.xMove, lp.yMove); + lp.closePath(); + } + isMove = true; + } + } + + prev = t; + dasher.next(); + } + } + + /** + * Dasher class provides dashing for particular dash style. + */ + class Dasher { + + /** + * The pos. + */ + double pos; + + /** + * The first. + */ + boolean close, visible, first; + + /** + * The dash. + */ + float dash[]; + + /** + * The phase. + */ + float phase; + + /** + * The index. + */ + int index; + + /** + * The iter. + */ + DashIterator iter; + + /** + * Instantiates a new dasher. + * + * @param dash + * the dash. + * @param phase + * the phase. + */ + Dasher(float dash[], float phase) { + this.dash = dash; + this.phase = phase; + index = 0; + pos = phase; + visible = true; + while (pos >= dash[index]) { + visible = !visible; + pos -= dash[index]; + index = (index + 1) % dash.length; + } + pos = -pos; + first = visible; + } + + /** + * Inits the. + * + * @param iter + * the iter. + */ + void init(DashIterator iter) { + this.iter = iter; + close = true; + } + + /** + * Checks if is open. + * + * @return true, if is open. + */ + boolean isOpen() { + return visible && pos < iter.length; + } + + /** + * Checks if is continue. + * + * @return true, if is continue. + */ + boolean isContinue() { + return !visible && pos > 0; + } + + /** + * Checks if is closed. + * + * @return true, if is closed. + */ + boolean isClosed() { + return close; + } + + /** + * Checks if is connected. + * + * @return true, if is connected. + */ + boolean isConnected() { + return first && !close; + } + + /** + * Eof. + * + * @return true, if successful. + */ + boolean eof() { + if (!close) { + pos -= iter.length; + return true; + } + if (pos >= iter.length) { + if (visible) { + pos -= iter.length; + return true; + } + close = pos == iter.length; + } + return false; + } + + /** + * Next. + */ + void next() { + if (close) { + pos += dash[index]; + index = (index + 1) % dash.length; + } else { + // Go back + index = (index + dash.length - 1) % dash.length; + pos -= dash[index]; + } + visible = !visible; + } + + /** + * Gets the value. + * + * @return the value. + */ + double getValue() { + double t = iter.getNext(pos); + return t < 0 ? 0 : (t > 1 ? 1 : t); + } + + } + + /** + * DashIterator class provides dashing for particular segment type. + */ + static abstract class DashIterator { + + /** + * The Constant FLATNESS. + */ + static final double FLATNESS = 1.0; + + /** + * The Class Line. + */ + static class Line extends DashIterator { + + /** + * Instantiates a new line. + * + * @param len + * the len. + */ + Line(double len) { + length = len; + } + + @Override + double getNext(double dashPos) { + return dashPos / length; + } + + } + + /** + * The Class Quad. + */ + static class Quad extends DashIterator { + + /** + * The val size. + */ + int valSize; + + /** + * The val pos. + */ + int valPos; + + /** + * The cur len. + */ + double curLen; + + /** + * The prev len. + */ + double prevLen; + + /** + * The last len. + */ + double lastLen; + + /** + * The values. + */ + double[] values; + + /** + * The step. + */ + double step; + + /** + * Instantiates a new quad. + * + * @param x1 + * the x1. + * @param y1 + * the y1. + * @param x2 + * the x2. + * @param y2 + * the y2. + * @param x3 + * the x3. + * @param y3 + * the y3. + */ + Quad(double x1, double y1, double x2, double y2, double x3, double y3) { + + double nx = x1 + x3 - x2 - x2; + double ny = y1 + y3 - y2 - y2; + + int n = (int)(1 + Math.sqrt(0.75 * (Math.abs(nx) + Math.abs(ny)) * FLATNESS)); + step = 1.0 / n; + + double ax = x1 + x3 - x2 - x2; + double ay = y1 + y3 - y2 - y2; + double bx = 2.0 * (x2 - x1); + double by = 2.0 * (y2 - y1); + + double dx1 = step * (step * ax + bx); + double dy1 = step * (step * ay + by); + double dx2 = step * (step * ax * 2.0); + double dy2 = step * (step * ay * 2.0); + double vx = x1; + double vy = y1; + + valSize = n; + values = new double[valSize]; + double pvx = vx; + double pvy = vy; + length = 0.0; + for (int i = 0; i < n; i++) { + vx += dx1; + vy += dy1; + dx1 += dx2; + dy1 += dy2; + double lx = vx - pvx; + double ly = vy - pvy; + values[i] = Math.sqrt(lx * lx + ly * ly); + length += values[i]; + pvx = vx; + pvy = vy; + } + + valPos = 0; + curLen = 0.0; + prevLen = 0.0; + } + + @Override + double getNext(double dashPos) { + double t = 2.0; + while (curLen <= dashPos && valPos < valSize) { + prevLen = curLen; + curLen += lastLen = values[valPos++]; + } + if (curLen > dashPos) { + t = (valPos - 1 + (dashPos - prevLen) / lastLen) * step; + } + return t; + } + + } + + /** + * The Class Cubic. + */ + static class Cubic extends DashIterator { + + /** + * The val size. + */ + int valSize; + + /** + * The val pos. + */ + int valPos; + + /** + * The cur len. + */ + double curLen; + + /** + * The prev len. + */ + double prevLen; + + /** + * The last len. + */ + double lastLen; + + /** + * The values. + */ + double[] values; + + /** + * The step. + */ + double step; + + /** + * Instantiates a new cubic. + * + * @param x1 + * the x1. + * @param y1 + * the y1. + * @param x2 + * the x2. + * @param y2 + * the y2. + * @param x3 + * the x3. + * @param y3 + * the y3. + * @param x4 + * the x4. + * @param y4 + * the y4. + */ + Cubic(double x1, double y1, double x2, double y2, double x3, double y3, double x4, + double y4) { + + double nx1 = x1 + x3 - x2 - x2; + double ny1 = y1 + y3 - y2 - y2; + double nx2 = x2 + x4 - x3 - x3; + double ny2 = y2 + y4 - y3 - y3; + + double max = Math.max(Math.abs(nx1) + Math.abs(ny1), Math.abs(nx2) + Math.abs(ny2)); + int n = (int)(1 + Math.sqrt(0.75 * max) * FLATNESS); + step = 1.0 / n; + + double ax = x4 - x1 + 3.0 * (x2 - x3); + double ay = y4 - y1 + 3.0 * (y2 - y3); + double bx = 3.0 * (x1 + x3 - x2 - x2); + double by = 3.0 * (y1 + y3 - y2 - y2); + double cx = 3.0 * (x2 - x1); + double cy = 3.0 * (y2 - y1); + + double dx1 = step * (step * (step * ax + bx) + cx); + double dy1 = step * (step * (step * ay + by) + cy); + double dx2 = step * (step * (step * ax * 6.0 + bx * 2.0)); + double dy2 = step * (step * (step * ay * 6.0 + by * 2.0)); + double dx3 = step * (step * (step * ax * 6.0)); + double dy3 = step * (step * (step * ay * 6.0)); + double vx = x1; + double vy = y1; + + valSize = n; + values = new double[valSize]; + double pvx = vx; + double pvy = vy; + length = 0.0; + for (int i = 0; i < n; i++) { + vx += dx1; + vy += dy1; + dx1 += dx2; + dy1 += dy2; + dx2 += dx3; + dy2 += dy3; + double lx = vx - pvx; + double ly = vy - pvy; + values[i] = Math.sqrt(lx * lx + ly * ly); + length += values[i]; + pvx = vx; + pvy = vy; + } + + valPos = 0; + curLen = 0.0; + prevLen = 0.0; + } + + @Override + double getNext(double dashPos) { + double t = 2.0; + while (curLen <= dashPos && valPos < valSize) { + prevLen = curLen; + curLen += lastLen = values[valPos++]; + } + if (curLen > dashPos) { + t = (valPos - 1 + (dashPos - prevLen) / lastLen) * step; + } + return t; + } + + } + + /** + * The length. + */ + double length; + + /** + * Gets the next. + * + * @param dashPos + * the dash pos. + * @return the next. + */ + abstract double getNext(double dashPos); + + } + + /** + * BufferedPath class provides work path storing and processing. + */ + static class BufferedPath { + + /** + * The Constant bufCapacity. + */ + private static final int bufCapacity = 10; + + /** + * The point shift. + */ + static int pointShift[] = { + 2, // MOVETO + 2, // LINETO + 4, // QUADTO + 6, // CUBICTO + 0 + }; // CLOSE + + /** + * The types. + */ + byte[] types; + + /** + * The points. + */ + float[] points; + + /** + * The type size. + */ + int typeSize; + + /** + * The point size. + */ + int pointSize; + + /** + * The x last. + */ + float xLast; + + /** + * The y last. + */ + float yLast; + + /** + * The x move. + */ + float xMove; + + /** + * The y move. + */ + float yMove; + + /** + * Instantiates a new buffered path. + */ + public BufferedPath() { + types = new byte[bufCapacity]; + points = new float[bufCapacity * 2]; + } + + /** + * Check buf. + * + * @param typeCount + * the type count. + * @param pointCount + * the point count. + */ + void checkBuf(int typeCount, int pointCount) { + if (typeSize + typeCount > types.length) { + byte tmp[] = new byte[typeSize + Math.max(bufCapacity, typeCount)]; + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(types, 0, tmp, 0, typeSize); + types = tmp; + } + if (pointSize + pointCount > points.length) { + float tmp[] = new float[pointSize + Math.max(bufCapacity * 2, pointCount)]; + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(points, 0, tmp, 0, pointSize); + points = tmp; + } + } + + /** + * Checks if is empty. + * + * @return true, if is empty. + */ + boolean isEmpty() { + return typeSize == 0; + } + + /** + * Clean. + */ + void clean() { + typeSize = 0; + pointSize = 0; + } + + /** + * Move to. + * + * @param x + * the x. + * @param y + * the y. + */ + void moveTo(double x, double y) { + checkBuf(1, 2); + types[typeSize++] = PathIterator.SEG_MOVETO; + points[pointSize++] = xMove = (float)x; + points[pointSize++] = yMove = (float)y; + } + + /** + * Line to. + * + * @param x + * the x. + * @param y + * the y. + */ + void lineTo(double x, double y) { + checkBuf(1, 2); + types[typeSize++] = PathIterator.SEG_LINETO; + points[pointSize++] = xLast = (float)x; + points[pointSize++] = yLast = (float)y; + } + + /** + * Quad to. + * + * @param x1 + * the x1. + * @param y1 + * the y1. + * @param x2 + * the x2. + * @param y2 + * the y2. + */ + void quadTo(double x1, double y1, double x2, double y2) { + checkBuf(1, 4); + types[typeSize++] = PathIterator.SEG_QUADTO; + points[pointSize++] = (float)x1; + points[pointSize++] = (float)y1; + points[pointSize++] = xLast = (float)x2; + points[pointSize++] = yLast = (float)y2; + } + + /** + * Cubic to. + * + * @param x1 + * the x1. + * @param y1 + * the y1. + * @param x2 + * the x2. + * @param y2 + * the y2. + * @param x3 + * the x3. + * @param y3 + * the y3. + */ + void cubicTo(double x1, double y1, double x2, double y2, double x3, double y3) { + checkBuf(1, 6); + types[typeSize++] = PathIterator.SEG_CUBICTO; + points[pointSize++] = (float)x1; + points[pointSize++] = (float)y1; + points[pointSize++] = (float)x2; + points[pointSize++] = (float)y2; + points[pointSize++] = xLast = (float)x3; + points[pointSize++] = yLast = (float)y3; + } + + /** + * Close path. + */ + void closePath() { + checkBuf(1, 0); + types[typeSize++] = PathIterator.SEG_CLOSE; + } + + /** + * Sets the last. + * + * @param x + * the x. + * @param y + * the y. + */ + void setLast(double x, double y) { + points[pointSize - 2] = xLast = (float)x; + points[pointSize - 1] = yLast = (float)y; + } + + /** + * Append. + * + * @param p + * the p. + */ + void append(BufferedPath p) { + checkBuf(p.typeSize, p.pointSize); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(p.points, 0, points, pointSize, p.pointSize); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(p.types, 0, types, typeSize, p.typeSize); + pointSize += p.pointSize; + typeSize += p.typeSize; + xLast = points[pointSize - 2]; + yLast = points[pointSize - 1]; + } + + /** + * Append reverse. + * + * @param p + * the p. + */ + void appendReverse(BufferedPath p) { + checkBuf(p.typeSize, p.pointSize); + // Skip last point, beacause it's the first point of the second path + for (int i = p.pointSize - 2; i >= 0; i -= 2) { + points[pointSize++] = p.points[i + 0]; + points[pointSize++] = p.points[i + 1]; + } + // Skip first type, beacuse it's always MOVETO + int closeIndex = 0; + for (int i = p.typeSize - 1; i >= 0; i--) { + byte type = p.types[i]; + if (type == PathIterator.SEG_MOVETO) { + types[closeIndex] = PathIterator.SEG_MOVETO; + types[typeSize++] = PathIterator.SEG_CLOSE; + } else { + if (type == PathIterator.SEG_CLOSE) { + closeIndex = typeSize; + } + types[typeSize++] = type; + } + } + xLast = points[pointSize - 2]; + yLast = points[pointSize - 1]; + } + + /** + * Join. + * + * @param p + * the p. + */ + void join(BufferedPath p) { + // Skip MOVETO + checkBuf(p.typeSize - 1, p.pointSize - 2); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(p.points, 2, points, pointSize, p.pointSize - 2); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(p.types, 1, types, typeSize, p.typeSize - 1); + pointSize += p.pointSize - 2; + typeSize += p.typeSize - 1; + xLast = points[pointSize - 2]; + yLast = points[pointSize - 1]; + } + + /** + * Combine. + * + * @param p + * the p. + */ + void combine(BufferedPath p) { + checkBuf(p.typeSize - 1, p.pointSize - 2); + // Skip last point, beacause it's the first point of the second path + for (int i = p.pointSize - 4; i >= 0; i -= 2) { + points[pointSize++] = p.points[i + 0]; + points[pointSize++] = p.points[i + 1]; + } + // Skip first type, beacuse it's always MOVETO + for (int i = p.typeSize - 1; i >= 1; i--) { + types[typeSize++] = p.types[i]; + } + xLast = points[pointSize - 2]; + yLast = points[pointSize - 1]; + } + + /** + * Creates the general path. + * + * @return the general path. + */ + GeneralPath createGeneralPath() { + GeneralPath p = new GeneralPath(); + int j = 0; + for (int i = 0; i < typeSize; i++) { + int type = types[i]; + switch (type) { + case PathIterator.SEG_MOVETO: + p.moveTo(points[j], points[j + 1]); + break; + case PathIterator.SEG_LINETO: + p.lineTo(points[j], points[j + 1]); + break; + case PathIterator.SEG_QUADTO: + p.quadTo(points[j], points[j + 1], points[j + 2], points[j + 3]); + break; + case PathIterator.SEG_CUBICTO: + p.curveTo(points[j], points[j + 1], points[j + 2], points[j + 3], + points[j + 4], points[j + 5]); + break; + case PathIterator.SEG_CLOSE: + p.closePath(); + break; + } + j += pointShift[type]; + } + return p; + } + + } + +} diff --git a/app/src/main/java/java/awt/BufferCapabilities.java b/app/src/main/java/java/awt/BufferCapabilities.java new file mode 100644 index 000000000..cd5fe7b1c --- /dev/null +++ b/app/src/main/java/java/awt/BufferCapabilities.java @@ -0,0 +1,195 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey A. Petrenko + * @version $Revision$ + */ + +package java.awt; + +/** + * The BufferCapabilities class represents the capabilities and other properties + * of the image buffers. + * + * @since Android 1.0 + */ +public class BufferCapabilities implements Cloneable { + + /** + * The front buffer capabilities. + */ + private final ImageCapabilities frontBufferCapabilities; + + /** + * The back buffer capabilities. + */ + private final ImageCapabilities backBufferCapabilities; + + /** + * The flip contents. + */ + private final FlipContents flipContents; + + /** + * Instantiates a new BufferCapabilities object. + * + * @param frontBufferCapabilities + * the front buffer capabilities, can not be null. + * @param backBufferCapabilities + * the the back and intermediate buffers capabilities, can not be + * null. + * @param flipContents + * the back buffer contents after page flipping, null if page + * flipping is not used. + */ + public BufferCapabilities(ImageCapabilities frontBufferCapabilities, + ImageCapabilities backBufferCapabilities, FlipContents flipContents) { + if (frontBufferCapabilities == null || backBufferCapabilities == null) { + throw new IllegalArgumentException(); + } + + this.frontBufferCapabilities = frontBufferCapabilities; + this.backBufferCapabilities = backBufferCapabilities; + this.flipContents = flipContents; + } + + /** + * Returns a copy of the BufferCapabilities object. + * + * @return a copy of the BufferCapabilities object. + */ + @Override + public Object clone() { + return new BufferCapabilities(frontBufferCapabilities, backBufferCapabilities, flipContents); + } + + /** + * Gets the image capabilities of the front buffer. + * + * @return the ImageCapabilities object represented capabilities of the + * front buffer. + */ + public ImageCapabilities getFrontBufferCapabilities() { + return frontBufferCapabilities; + } + + /** + * Gets the image capabilities of the back buffer. + * + * @return the ImageCapabilities object represented capabilities of the back + * buffer. + */ + public ImageCapabilities getBackBufferCapabilities() { + return backBufferCapabilities; + } + + /** + * Gets the flip contents of the back buffer after page-flipping. + * + * @return the FlipContents of the back buffer after page-flipping. + */ + public FlipContents getFlipContents() { + return flipContents; + } + + /** + * Checks if the buffer strategy uses page flipping. + * + * @return true, if the buffer strategy uses page flipping, false otherwise. + */ + public boolean isPageFlipping() { + return flipContents != null; + } + + /** + * Checks if page flipping is only available in full-screen mode. + * + * @return true, if page flipping is only available in full-screen mode, + * false otherwise. + */ + public boolean isFullScreenRequired() { + return false; + } + + /** + * Checks if page flipping can be performed using more than two buffers. + * + * @return true, if page flipping can be performed using more than two + * buffers, false otherwise. + */ + public boolean isMultiBufferAvailable() { + return false; + } + + /** + * The FlipContents class represents a set of possible back buffer contents + * after page-flipping. + * + * @since Android 1.0 + */ + public static final class FlipContents { + + /** + * The back buffered contents are cleared with the background color + * after flipping. + */ + public static final FlipContents BACKGROUND = new FlipContents(); + + /** + * The back buffered contents are copied to the front buffer before + * flipping. + */ + public static final FlipContents COPIED = new FlipContents(); + + /** + * The back buffer contents are the prior contents of the front buffer. + */ + public static final FlipContents PRIOR = new FlipContents(); + + /** + * The back buffer contents are undefined after flipping + */ + public static final FlipContents UNDEFINED = new FlipContents(); + + /** + * Instantiates a new flip contents. + */ + private FlipContents() { + + } + + /** + * Returns the hash code of the FlipContents object. + * + * @return the hash code of the FlipContents object. + */ + @Override + public int hashCode() { + return super.hashCode(); + } + + /** + * Returns the String representation of the FlipContents object. + * + * @return the string + */ + @Override + public String toString() { + return super.toString(); + } + } +} diff --git a/app/src/main/java/java/awt/Canvas.java b/app/src/main/java/java/awt/Canvas.java index d4691bc68..217684ee8 100644 --- a/app/src/main/java/java/awt/Canvas.java +++ b/app/src/main/java/java/awt/Canvas.java @@ -2,31 +2,10 @@ package java.awt; import java.awt.image.*; import net.kdt.pojavlaunch.*; +import com.android.internal.awt.*; public class Canvas extends Component { - private Graphics graphics; - public Canvas() { - graphics = new Graphics(new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB)); } - - public void setPreferredSize(Dimension dim){ - } - - public boolean isDisplayable(){ - return true; - } - - public Graphics getGraphics() { - return graphics; - } - - public int getWidth() { - return 1280; - } - - public int getHeight() { - return 720; - } } diff --git a/app/src/main/java/java/awt/Color.java b/app/src/main/java/java/awt/Color.java index 99f966a31..93c532d78 100644 --- a/app/src/main/java/java/awt/Color.java +++ b/app/src/main/java/java/awt/Color.java @@ -1,287 +1,902 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ + package java.awt; +import java.awt.color.ColorSpace; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.image.ColorModel; +import java.awt.image.DataBufferInt; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; import java.io.Serializable; +import java.util.Arrays; -public class Color implements Serializable { - public static final Color black = new Color(0, 0, 0); - public static final Color blue = new Color(0, 0, 255); - public static final Color cyan = new Color(0, 255, 255); - public static final Color darkGray = new Color(64, 64, 64); - public static final Color gray = new Color(128, 128, 128); - public static final Color green = new Color(0, 255, 0); - public static final Color lightGray = new Color(192, 192, 192); - public static final Color magenta = new Color(255, 0, 255); - public static final Color orange = new Color(255, 200, 0); - public static final Color pink = new Color(255, 175, 175); - public static final Color red = new Color(255, 0, 0); +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Color class defines colors in the default sRGB color space or in the + * specified ColorSpace. Every Color contains alpha value. The alpha value + * defines the transparency of a color and can be represented by a float value + * in the range 0.0 - 1.0 or 0 - 255. + * + * @since Android 1.0 + */ +public class Color implements Paint, Serializable { + + /** + * The Constant serialVersionUID. + */ private static final long serialVersionUID = 118526816881161077L; + + /* + * The values of the following colors are based on 1.5 release behavior + * which can be revealed using the following or similar code: Color c = + * Color.white; System.out.println(c); + */ + + /** + * The color white. + */ public static final Color white = new Color(255, 255, 255); - public static final Color yellow = new Color(255, 255, 0); - public static final Color BLACK = black; - public static final Color BLUE = blue; - public static final Color CYAN = cyan; - public static final Color DARK_GRAY = darkGray; - public static final Color GRAY = gray; - public static final Color GREEN = green; - public static final Color LIGHT_GRAY = lightGray; - public static final Color MAGENTA = magenta; - private static final int MIN_SCALABLE = 3; - public static final Color ORANGE = orange; - public static final Color PINK = pink; - public static final Color RED = red; - private static final double SCALE_FACTOR = 0.7d; + + /** + * The color white. + */ public static final Color WHITE = white; + + /** + * The color light gray. + */ + public static final Color lightGray = new Color(192, 192, 192); + + /** + * The color light gray. + */ + public static final Color LIGHT_GRAY = lightGray; + + /** + * The color gray. + */ + public static final Color gray = new Color(128, 128, 128); + + /** + * The color gray. + */ + public static final Color GRAY = gray; + + /** + * The color dark gray. + */ + public static final Color darkGray = new Color(64, 64, 64); + + /** + * The color dark gray. + */ + public static final Color DARK_GRAY = darkGray; + + /** + * The color black. + */ + public static final Color black = new Color(0, 0, 0); + + /** + * The color black. + */ + public static final Color BLACK = black; + + /** + * The color red. + */ + public static final Color red = new Color(255, 0, 0); + + /** + * The color red. + */ + public static final Color RED = red; + + /** + * The color pink. + */ + public static final Color pink = new Color(255, 175, 175); + + /** + * The color pink. + */ + public static final Color PINK = pink; + + /** + * The color orange. + */ + public static final Color orange = new Color(255, 200, 0); + + /** + * The color orange. + */ + public static final Color ORANGE = orange; + + /** + * The color yellow. + */ + public static final Color yellow = new Color(255, 255, 0); + + /** + * The color yellow. + */ public static final Color YELLOW = yellow; - private float falpha; - private float[] frgbvalue; - private float[] fvalue; + + /** + * The color green. + */ + public static final Color green = new Color(0, 255, 0); + + /** + * The color green. + */ + public static final Color GREEN = green; + + /** + * The color magenta. + */ + public static final Color magenta = new Color(255, 0, 255); + + /** + * The color magenta. + */ + public static final Color MAGENTA = magenta; + + /** + * The color cyan. + */ + public static final Color cyan = new Color(0, 255, 255); + + /** + * The color cyan. + */ + public static final Color CYAN = cyan; + + /** + * The color blue. + */ + public static final Color blue = new Color(0, 0, 255); + + /** + * The color blue. + */ + public static final Color BLUE = blue; + + /** + * integer RGB value. + */ int value; + /** + * Float sRGB value. + */ + private float[] frgbvalue; + + /** + * Color in an arbitrary color space with float components. If + * null, other value should be used. + */ + private float fvalue[]; + + /** + * Float alpha value. If frgbvalue is null, this is not valid data. + */ + private float falpha; + + /** + * The color's color space if applicable. + */ + private ColorSpace cs; + + /* + * The value of the SCALE_FACTOR is based on 1.5 release behavior which can + * be revealed using the following code: Color c = new Color(100, 100, 100); + * Color bc = c.brighter(); System.out.println("Brighter factor: " + + * ((float)c.getRed())/((float)bc.getRed())); Color dc = c.darker(); + * System.out.println("Darker factor: " + + * ((float)dc.getRed())/((float)c.getRed())); The result is the same for + * brighter and darker methods, so we need only one scale factor for both. + */ + /** + * The Constant SCALE_FACTOR. + */ + private static final double SCALE_FACTOR = 0.7; + + /** + * The Constant MIN_SCALABLE. + */ + private static final int MIN_SCALABLE = 3; // should increase when + + // multiplied by SCALE_FACTOR + + /** + * The current paint context. + */ + transient private PaintContext currentPaintContext; + + /** + * Creates a color in the specified ColorSpace, the specified color + * components and the specified alpha. + * + * @param cspace + * the ColorSpace to be used to define the components. + * @param components + * the components. + * @param alpha + * the alpha. + */ + public Color(ColorSpace cspace, float[] components, float alpha) { + int nComps = cspace.getNumComponents(); + float comp; + fvalue = new float[nComps]; + + for (int i = 0; i < nComps; i++) { + comp = components[i]; + if (comp < 0.0f || comp > 1.0f) { + // awt.107=Color parameter outside of expected range: component + // {0}. + throw new IllegalArgumentException(Messages.getString("awt.107", i)); //$NON-NLS-1$ + } + fvalue[i] = components[i]; + } + + if (alpha < 0.0f || alpha > 1.0f) { + // awt.108=Alpha value outside of expected range. + throw new IllegalArgumentException(Messages.getString("awt.108")); //$NON-NLS-1$ + } + falpha = alpha; + + cs = cspace; + + frgbvalue = cs.toRGB(fvalue); + + value = ((int)(frgbvalue[2] * 255 + 0.5)) | (((int)(frgbvalue[1] * 255 + 0.5)) << 8) + | (((int)(frgbvalue[0] * 255 + 0.5)) << 16) | (((int)(falpha * 255 + 0.5)) << 24); + } + + /** + * Instantiates a new sRGB color with the specified combined RGBA value + * consisting of the alpha component in bits 24-31, the red component in + * bits 16-23, the green component in bits 8-15, and the blue component in + * bits 0-7. If the hasalpha argument is false, the alpha has default value + * - 255. + * + * @param rgba + * the RGBA components. + * @param hasAlpha + * the alpha parameter is true if alpha bits are valid, false + * otherwise. + */ public Color(int rgba, boolean hasAlpha) { - if (hasAlpha) { - this.value = rgba; + if (!hasAlpha) { + value = rgba | 0xFF000000; } else { - this.value = -16777216 | rgba; + value = rgba; } } + /** + * Instantiates a new color with the specified red, green, blue and alpha + * components. + * + * @param r + * the red component. + * @param g + * the green component. + * @param b + * the blue component. + * @param a + * the alpha component. + */ public Color(int r, int g, int b, int a) { - if ((r & 255) == r && (g & 255) == g && (b & 255) == b && (a & 255) == a) { - this.value = (((g << 8) | b) | (r << 16)) | (a << 24); - return; + if ((r & 0xFF) != r || (g & 0xFF) != g || (b & 0xFF) != b || (a & 0xFF) != a) { + // awt.109=Color parameter outside of expected range. + throw new IllegalArgumentException(Messages.getString("awt.109")); //$NON-NLS-1$ } - throw new IllegalArgumentException("Color parameter outside of expected range"); + value = b | (g << 8) | (r << 16) | (a << 24); } + /** + * Instantiates a new opaque sRGB color with the specified red, green, and + * blue values. The Alpha component is set to the default - 1.0. + * + * @param r + * the red component. + * @param g + * the green component. + * @param b + * the blue component. + */ public Color(int r, int g, int b) { - if ((r & 255) == r && (g & 255) == g && (b & 255) == b) { - this.value = (((g << 8) | b) | (r << 16)) | -16777216; - return; + if ((r & 0xFF) != r || (g & 0xFF) != g || (b & 0xFF) != b) { + // awt.109=Color parameter outside of expected range. + throw new IllegalArgumentException(Messages.getString("awt.109")); //$NON-NLS-1$ } - throw new IllegalArgumentException("Color parameter outside of expected range"); + // 0xFF for alpha channel + value = b | (g << 8) | (r << 16) | 0xFF000000; } + /** + * Instantiates a new sRGB color with the specified RGB value consisting of + * the red component in bits 16-23, the green component in bits 8-15, and + * the blue component in bits 0-7. Alpha has default value - 255. + * + * @param rgb + * the RGB components. + */ public Color(int rgb) { - this.value = -16777216 | rgb; + value = rgb | 0xFF000000; } + /** + * Instantiates a new color with the specified red, green, blue and alpha + * components. + * + * @param r + * the red component. + * @param g + * the green component. + * @param b + * the blue component. + * @param a + * the alpha component. + */ public Color(float r, float g, float b, float a) { - this((int) (((double) (r * 255.0f)) + 0.5d), (int) (((double) (g * 255.0f)) + 0.5d), (int) (((double) (b * 255.0f)) + 0.5d), (int) (((double) (a * 255.0f)) + 0.5d)); - this.falpha = a; - this.fvalue = new float[MIN_SCALABLE]; - this.fvalue[0] = r; - this.fvalue[1] = g; - this.fvalue[2] = b; - this.frgbvalue = this.fvalue; + this((int)(r * 255 + 0.5), (int)(g * 255 + 0.5), (int)(b * 255 + 0.5), (int)(a * 255 + 0.5)); + falpha = a; + fvalue = new float[3]; + fvalue[0] = r; + fvalue[1] = g; + fvalue[2] = b; + frgbvalue = fvalue; } + /** + * Instantiates a new color with the specified red, green, and blue + * components and default alpha value - 1.0. + * + * @param r + * the red component. + * @param g + * the green component. + * @param b + * the blue component. + */ public Color(float r, float g, float b) { this(r, g, b, 1.0f); } - public String toString() { - return getClass().getName() + "[r=" + getRed() + ",g=" + getGreen() + ",b=" + getBlue() + "]"; + public PaintContext createContext(ColorModel cm, Rectangle r, Rectangle2D r2d, + AffineTransform xform, RenderingHints rhs) { + if (currentPaintContext != null) { + return currentPaintContext; + } + currentPaintContext = new Color.ColorPaintContext(value); + return currentPaintContext; } + /** + * Returns a string representation of the Color object. + * + * @return the string representation of the Color object. + */ + @Override + public String toString() { + /* + * The format of the string is based on 1.5 release behavior which can + * be revealed using the following code: Color c = new Color(1, 2, 3); + * System.out.println(c); + */ + + return getClass().getName() + "[r=" + getRed() + //$NON-NLS-1$ + ",g=" + getGreen() + //$NON-NLS-1$ + ",b=" + getBlue() + //$NON-NLS-1$ + "]"; //$NON-NLS-1$ + } + + /** + * Compares the specified Object to the Color. + * + * @param obj + * the Object to be compared. + * @return true, if the specified Object is a Color whose value is equal to + * this Color, false otherwise. + */ + @Override public boolean equals(Object obj) { - if ((obj instanceof Color) && ((Color) obj).value == this.value) { - return true; + if (obj instanceof Color) { + return ((Color)obj).value == this.value; } return false; } - public Color darker() { - return new Color((int) (((double) getRed()) * SCALE_FACTOR), (int) (((double) getGreen()) * SCALE_FACTOR), (int) (((double) getBlue()) * SCALE_FACTOR)); + /** + * Returns a float array containing the color and alpha components of the + * Color in the specified ColorSpace. + * + * @param colorSpace + * the specified ColorSpace. + * @param components + * the results of this method will be written to this float + * array. If null, a float array will be created. + * @return the color and alpha components in a float array. + */ + public float[] getComponents(ColorSpace colorSpace, float[] components) { + int nComps = colorSpace.getNumComponents(); + if (components == null) { + components = new float[nComps + 1]; + } + + getColorComponents(colorSpace, components); + + if (frgbvalue != null) { + components[nComps] = falpha; + } else { + components[nComps] = getAlpha() / 255f; + } + + return components; } + /** + * Returns a float array containing the color components of the Color in the + * specified ColorSpace. + * + * @param colorSpace + * the specified ColorSpace. + * @param components + * the results of this method will be written to this float + * array. If null, a float array will be created. + * @return the color components in a float array. + */ + public float[] getColorComponents(ColorSpace colorSpace, float[] components) { + float[] cieXYZComponents = getColorSpace().toCIEXYZ(getColorComponents(null)); + float[] csComponents = colorSpace.fromCIEXYZ(cieXYZComponents); + + if (components == null) { + return csComponents; + } + + for (int i = 0; i < csComponents.length; i++) { + components[i] = csComponents[i]; + } + + return components; + } + + /** + * Gets the ColorSpace of this Color. + * + * @return the ColorSpace object. + */ + public ColorSpace getColorSpace() { + if (cs == null) { + cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); + } + + return cs; + } + + /** + * Creates a new Color which is a darker than this Color according to a + * fixed scale factor. + * + * @return the darker Color. + */ + public Color darker() { + return new Color((int)(getRed() * SCALE_FACTOR), (int)(getGreen() * SCALE_FACTOR), + (int)(getBlue() * SCALE_FACTOR)); + } + + /** + * Creates a new Color which is a brighter than this Color. + * + * @return the brighter Color. + */ public Color brighter() { + int r = getRed(); int b = getBlue(); int g = getGreen(); + if (r == 0 && b == 0 && g == 0) { - return new Color((int) MIN_SCALABLE, (int) MIN_SCALABLE, (int) MIN_SCALABLE); + return new Color(MIN_SCALABLE, MIN_SCALABLE, MIN_SCALABLE); } - if (r >= MIN_SCALABLE || r == 0) { - r = (int) (((double) r) / SCALE_FACTOR); - if (r > 255) { - r = 255; - } - } else { + + if (r < MIN_SCALABLE && r != 0) { r = MIN_SCALABLE; - } - if (b >= MIN_SCALABLE || b == 0) { - b = (int) (((double) b) / SCALE_FACTOR); - if (b > 255) { - b = 255; - } } else { + r = (int)(r / SCALE_FACTOR); + r = (r > 255) ? 255 : r; + } + + if (b < MIN_SCALABLE && b != 0) { b = MIN_SCALABLE; - } - if (g >= MIN_SCALABLE || g == 0) { - g = (int) (((double) g) / SCALE_FACTOR); - if (g > 255) { - g = 255; - } } else { - g = MIN_SCALABLE; + b = (int)(b / SCALE_FACTOR); + b = (b > 255) ? 255 : b; } + + if (g < MIN_SCALABLE && g != 0) { + g = MIN_SCALABLE; + } else { + g = (int)(g / SCALE_FACTOR); + g = (g > 255) ? 255 : g; + } + return new Color(r, g, b); } + /** + * Returns a float array containing the color and alpha components of the + * Color in the default sRGB color space. + * + * @param components + * the results of this method will be written to this float + * array. A new float array will be created if this argument is + * null. + * @return the RGB color and alpha components in a float array. + */ public float[] getRGBComponents(float[] components) { if (components == null) { components = new float[4]; } - if (this.frgbvalue != null) { - components[MIN_SCALABLE] = this.falpha; + + if (frgbvalue != null) { + components[3] = falpha; } else { - components[MIN_SCALABLE] = ((float) getAlpha()) / 255.0f; + components[3] = getAlpha() / 255f; } + getRGBColorComponents(components); + return components; } + /** + * Returns a float array containing the color components of the Color in the + * default sRGB color space. + * + * @param components + * the results of this method will be written to this float + * array. A new float array will be created if this argument is + * null. + * @return the RGB color components in a float array. + */ public float[] getRGBColorComponents(float[] components) { if (components == null) { - components = new float[MIN_SCALABLE]; + components = new float[3]; } - if (this.frgbvalue != null) { - components[2] = this.frgbvalue[2]; - components[1] = this.frgbvalue[1]; - components[0] = this.frgbvalue[0]; + + if (frgbvalue != null) { + components[2] = frgbvalue[2]; + components[1] = frgbvalue[1]; + components[0] = frgbvalue[0]; } else { - components[2] = ((float) getBlue()) / 255.0f; - components[1] = ((float) getGreen()) / 255.0f; - components[0] = ((float) getRed()) / 255.0f; + components[2] = getBlue() / 255f; + components[1] = getGreen() / 255f; + components[0] = getRed() / 255f; } + return components; } + /** + * Returns a float array which contains the color and alpha components of + * the Color in the ColorSpace of the Color. + * + * @param components + * the results of this method will be written to this float + * array. A new float array will be created if this argument is + * null. + * @return the color and alpha components in a float array. + */ public float[] getComponents(float[] components) { - if (this.fvalue == null) { + if (fvalue == null) { return getRGBComponents(components); } - int nColorComps = this.fvalue.length; + + int nColorComps = fvalue.length; + if (components == null) { - components = new float[(nColorComps + 1)]; + components = new float[nColorComps + 1]; } + getColorComponents(components); - components[nColorComps] = this.falpha; + + components[nColorComps] = falpha; + return components; } + /** + * Returns a float array which contains the color components of the Color in + * the ColorSpace of the Color. + * + * @param components + * the results of this method will be written to this float + * array. A new float array will be created if this argument is + * null. + * @return the color components in a float array. + */ public float[] getColorComponents(float[] components) { - if (this.fvalue == null) { + if (fvalue == null) { return getRGBColorComponents(components); } + if (components == null) { - components = new float[this.fvalue.length]; + components = new float[fvalue.length]; } - for (int i = 0; i < this.fvalue.length; i++) { - components[i] = this.fvalue[i]; + + for (int i = 0; i < fvalue.length; i++) { + components[i] = fvalue[i]; } + return components; } + /** + * Returns a hash code of this Color object. + * + * @return a hash code of this Color object. + */ + @Override public int hashCode() { - return this.value; + return value; } + public int getTransparency() { + switch (getAlpha()) { + case 0xff: + return Transparency.OPAQUE; + case 0: + return Transparency.BITMASK; + default: + return Transparency.TRANSLUCENT; + } + } + + /** + * Gets the red component of the Color in the range 0-255. + * + * @return the red component of the Color. + */ public int getRed() { - return (this.value >> 16) & 255; + return (value >> 16) & 0xFF; } + /** + * Gets the RGB value that represents the color in the default sRGB + * ColorModel. + * + * @return the RGB color value in the default sRGB ColorModel. + */ public int getRGB() { - return this.value; + return value; } + /** + * Gets the green component of the Color in the range 0-255. + * + * @return the green component of the Color. + */ public int getGreen() { - return (this.value >> 8) & 255; + return (value >> 8) & 0xFF; } + /** + * Gets the blue component of the Color in the range 0-255. + * + * @return the blue component of the Color. + */ public int getBlue() { - return this.value & 255; + return value & 0xFF; } + /** + * Gets the alpha component of the Color in the range 0-255. + * + * @return the alpha component of the Color. + */ public int getAlpha() { - return (this.value >> 24) & 255; + return (value >> 24) & 0xFF; } + /** + * Gets the Color from the specified string, or returns the Color specified + * by the second parameter. + * + * @param nm + * the specified string. + * @param def + * the default Color. + * @return the color from the specified string, or the Color specified by + * the second parameter. + */ public static Color getColor(String nm, Color def) { Integer integer = Integer.getInteger(nm); - return integer == null ? def : new Color(integer.intValue()); + + if (integer == null) { + return def; + } + + return new Color(integer.intValue()); } + /** + * Gets the Color from the specified string, or returns the Color converted + * from the second parameter. + * + * @param nm + * the specified string. + * @param def + * the default Color. + * @return the color from the specified string, or the Color converted from + * the second parameter. + */ public static Color getColor(String nm, int def) { Integer integer = Integer.getInteger(nm); + if (integer == null) { return new Color(def); } + return new Color(integer.intValue()); } + /** + * Gets the Color from the specified String. + * + * @param nm + * the specified string. + * @return the Color object, or null. + */ public static Color getColor(String nm) { Integer integer = Integer.getInteger(nm); + if (integer == null) { return null; } + return new Color(integer.intValue()); } + /** + * Decodes a String to an integer and returns the specified opaque Color. + * + * @param nm + * the String which represents an opaque color as a 24-bit + * integer. + * @return the Color object from the given String. + * @throws NumberFormatException + * if the specified string can not be converted to an integer. + */ public static Color decode(String nm) throws NumberFormatException { - return new Color(Integer.decode(nm).intValue()); + Integer integer = Integer.decode(nm); + return new Color(integer.intValue()); } + /** + * Gets a Color object using the specified values of the HSB color model. + * + * @param h + * the hue component of the Color. + * @param s + * the saturation of the Color. + * @param b + * the brightness of the Color. + * @return a color object with the specified hue, saturation and brightness + * values. + */ public static Color getHSBColor(float h, float s, float b) { return new Color(HSBtoRGB(h, s, b)); } + /** + * Converts the Color specified by the RGB model to an equivalent color in + * the HSB model. + * + * @param r + * the red component. + * @param g + * the green component. + * @param b + * the blue component. + * @param hsbvals + * the array of result hue, saturation, brightness values or + * null. + * @return the float array of hue, saturation, brightness values. + */ public static float[] RGBtoHSB(int r, int g, int b, float[] hsbvals) { - float S; - float H; if (hsbvals == null) { - hsbvals = new float[MIN_SCALABLE]; + hsbvals = new float[3]; } + int V = Math.max(b, Math.max(r, g)); int temp = Math.min(b, Math.min(r, g)); - float B = ((float) V) / 255.0f; + + float H, S, B; + + B = V / 255.f; + if (V == temp) { - S = 0.0f; - H = 0.0f; + H = S = 0; } else { - S = ((float) (V - temp)) / ((float) V); - float Cr = ((float) (V - r)) / ((float) (V - temp)); - float Cg = ((float) (V - g)) / ((float) (V - temp)); - float Cb = ((float) (V - b)) / ((float) (V - temp)); + S = (V - temp) / ((float)V); + + float Cr = (V - r) / (float)(V - temp); + float Cg = (V - g) / (float)(V - temp); + float Cb = (V - b) / (float)(V - temp); + if (r == V) { H = Cb - Cg; } else if (g == V) { - H = (2.0f + Cr) - Cb; + H = 2 + Cr - Cb; } else { - H = (4.0f + Cg) - Cr; + H = 4 + Cg - Cr; } - H /= 6.0f; - if (H < 0.0f) { - H += 1.0f; + + H /= 6.f; + if (H < 0) { + H++; } } + hsbvals[0] = H; hsbvals[1] = S; hsbvals[2] = B; + return hsbvals; } + /** + * Converts the Color specified by the HSB model to an equivalent color in + * the default RGB model. + * + * @param hue + * the hue component of the Color. + * @param saturation + * the saturation of the Color. + * @param brightness + * the brightness of the Color. + * @return the RGB value of the color with the specified hue, saturation and + * brightness. + */ public static int HSBtoRGB(float hue, float saturation, float brightness) { - float fr; - float fg; - float fb; - if (saturation != 0.0f) { - float H = (hue - ((float) Math.floor((double) hue))) * 6.0f; - int I = (int) Math.floor((double) H); - float F = H - ((float) I); - float M = brightness * (1.0f - saturation); - float N = brightness * (1.0f - (saturation * F)); - float K = brightness * (1.0f - ((1.0f - F) * saturation)); + float fr, fg, fb; + + if (saturation == 0) { + fr = fg = fb = brightness; + } else { + float H = (hue - (float)Math.floor(hue)) * 6; + int I = (int)Math.floor(H); + float F = H - I; + float M = brightness * (1 - saturation); + float N = brightness * (1 - saturation * F); + float K = brightness * (1 - saturation * (1 - F)); + switch (I) { case 0: fr = brightness; @@ -298,7 +913,7 @@ public class Color implements Serializable { fg = brightness; fb = K; break; - case MIN_SCALABLE /*3*/: + case 3: fr = M; fg = N; fb = brightness; @@ -314,16 +929,62 @@ public class Color implements Serializable { fb = N; break; default: - fg = 0.0f; - fb = 0.0f; - fr = 0.0f; - break; + fr = fb = fg = 0; // impossible, to supress compiler error } } - fb = brightness; - fg = brightness; - fr = brightness; - return (((((int) ((((double) fr) * 255.0d) + 0.5d)) << 16) | (((int) ((((double) fg) * 255.0d) + 0.5d)) << 8)) | ((int) ((((double) fb) * 255.0d) + 0.5d))) | -16777216; + + int r = (int)(fr * 255. + 0.5); + int g = (int)(fg * 255. + 0.5); + int b = (int)(fb * 255. + 0.5); + + return (r << 16) | (g << 8) | b | 0xFF000000; + } + + /** + * The Class ColorPaintContext. + */ + class ColorPaintContext implements PaintContext { + + /** + * The RGB value. + */ + int rgbValue; + + /** + * The saved raster. + */ + WritableRaster savedRaster = null; + + /** + * Instantiates a new color paint context. + * + * @param rgb + * the RGB value. + */ + protected ColorPaintContext(int rgb) { + rgbValue = rgb; + } + + public void dispose() { + savedRaster = null; + } + + public ColorModel getColorModel() { + return ColorModel.getRGBdefault(); + } + + public Raster getRaster(int x, int y, int w, int h) { + if (savedRaster == null || w != savedRaster.getWidth() || h != savedRaster.getHeight()) { + savedRaster = getColorModel().createCompatibleWritableRaster(w, h); + + // Suppose we have here simple INT/RGB color/sample model + DataBufferInt intBuffer = (DataBufferInt)savedRaster.getDataBuffer(); + int rgbValues[] = intBuffer.getData(); + int rgbFillValue = rgbValue; + Arrays.fill(rgbValues, rgbFillValue); + } + + return savedRaster; + } } } - diff --git a/app/src/main/java/java/awt/Component.java b/app/src/main/java/java/awt/Component.java index cea2553a2..a4cf22a5f 100644 --- a/app/src/main/java/java/awt/Component.java +++ b/app/src/main/java/java/awt/Component.java @@ -1,59 +1,3958 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package java.awt; -import java.beans.*; -import org.apache.harmony.awt.wtk.*; -public class Component { - +//import java.awt.dnd.DropTarget; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.HierarchyBoundsListener; +import java.awt.event.HierarchyEvent; +import java.awt.event.HierarchyListener; +import java.awt.event.InputMethodEvent; +import java.awt.event.InputMethodListener; +import java.awt.event.InvocationEvent; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; +import java.awt.event.PaintEvent; +import java.awt.event.WindowEvent; +import java.awt.im.InputContext; +import java.awt.im.InputMethodRequests; +import java.awt.image.BufferStrategy; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.image.VolatileImage; +import java.awt.image.WritableRaster; +import java.awt.peer.ComponentPeer; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.Serializable; +import java.lang.reflect.Array; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.Collection; +import java.util.EventListener; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +//???AWT +//import javax.accessibility.Accessible; +//import javax.accessibility.AccessibleComponent; +//import javax.accessibility.AccessibleContext; +//import javax.accessibility.AccessibleRole; +//import javax.accessibility.AccessibleState; +//import javax.accessibility.AccessibleStateSet; + +import org.apache.harmony.awt.ClipRegion; //import org.apache.harmony.awt.FieldsAccessor; +import org.apache.harmony.awt.gl.MultiRectArea; +import org.apache.harmony.awt.internal.nls.Messages; +import org.apache.harmony.awt.state.State; //import org.apache.harmony.awt.text.TextFieldKit; +//import org.apache.harmony.awt.text.TextKit; +import org.apache.harmony.awt.wtk.NativeWindow; +import org.apache.harmony.luni.util.NotImplementedException; +import com.android.internal.awt.*; +import javax.accessibility.*; + +/** + * The abstract Component class specifies an object with a graphical + * representation that can be displayed on the screen and that can interact with + * the user (for example: scrollbars, buttons, checkboxes). + * + * @since Android 1.0 + */ +public abstract class Component implements ImageObserver, MenuContainer, Serializable { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = -7644114512714619750L; + + /** + * The Constant TOP_ALIGNMENT indicates the top alignment of the component. + */ + public static final float TOP_ALIGNMENT = 0.0f; + + /** + * The Constant CENTER_ALIGNMENT indicates the center alignment of the + * component. + */ + public static final float CENTER_ALIGNMENT = 0.5f; + + /** + * The Constant BOTTOM_ALIGNMENT indicates the bottom alignment of the + * component. + */ + public static final float BOTTOM_ALIGNMENT = 1.0f; + + /** + * The Constant LEFT_ALIGNMENT indicates the left alignment of the + * component. + */ + public static final float LEFT_ALIGNMENT = 0.0f; + + /** + * The Constant RIGHT_ALIGNMENT indicates the right alignment of the + * component. + */ + public static final float RIGHT_ALIGNMENT = 1.0f; + + /** + * The Constant childClassesFlags. + */ + private static final Hashtable, Boolean> childClassesFlags = new Hashtable, Boolean>(); + + /** + * The Constant peer. + */ + protected static final ComponentPeer peer = new ComponentPeer() { + }; + + /** + * The Constant incrementalImageUpdate. + */ + private static final boolean incrementalImageUpdate; + + /** + * The toolkit. + */ + final transient Toolkit toolkit = Toolkit.getDefaultToolkit(); + + // ???AWT + /* + * protected abstract class AccessibleAWTComponent extends AccessibleContext + * implements Serializable, AccessibleComponent { private static final long + * serialVersionUID = 642321655757800191L; protected class + * AccessibleAWTComponentHandler implements ComponentListener { protected + * AccessibleAWTComponentHandler() { } public void + * componentHidden(ComponentEvent e) { if (behaviour.isLightweight()) { + * return; } firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY, + * AccessibleState.VISIBLE, null); } public void + * componentMoved(ComponentEvent e) { } public void + * componentResized(ComponentEvent e) { } public void + * componentShown(ComponentEvent e) { if (behaviour.isLightweight()) { + * return; } firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY, + * null, AccessibleState.VISIBLE); } } protected class + * AccessibleAWTFocusHandler implements FocusListener { public void + * focusGained(FocusEvent e) { if (behaviour.isLightweight()) { return; } + * firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY, null, + * AccessibleState.FOCUSED); } public void focusLost(FocusEvent e) { if + * (behaviour.isLightweight()) { return; } + * firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY, + * AccessibleState.FOCUSED, null); } } protected ComponentListener + * + + + AWTComponentHandler; protected FocusListener + * accessibleAWTFocusHandler; + */ + /* + * Number of registered property change listeners. + */ + /* + * int listenersCount; public void addFocusListener(FocusListener l) { + * Component.this.addFocusListener(l); } + * @Override public void addPropertyChangeListener(PropertyChangeListener + * listener) { toolkit.lockAWT(); try { + * super.addPropertyChangeListener(listener); listenersCount++; if + * (accessibleAWTComponentHandler == null) { accessibleAWTComponentHandler = + * new AccessibleAWTComponentHandler(); + * Component.this.addComponentListener(accessibleAWTComponentHandler); } if + * (accessibleAWTFocusHandler == null) { accessibleAWTFocusHandler = new + * AccessibleAWTFocusHandler(); + * Component.this.addFocusListener(accessibleAWTFocusHandler); } } finally { + * toolkit.unlockAWT(); } } public boolean contains(Point p) { + * toolkit.lockAWT(); try { return Component.this.contains(p); } finally { + * toolkit.unlockAWT(); } } public Accessible getAccessibleAt(Point arg0) { + * toolkit.lockAWT(); try { return null; } finally { toolkit.unlockAWT(); } + * } public Color getBackground() { toolkit.lockAWT(); try { return + * Component.this.getBackground(); } finally { toolkit.unlockAWT(); } } + * public Rectangle getBounds() { toolkit.lockAWT(); try { return + * Component.this.getBounds(); } finally { toolkit.unlockAWT(); } } public + * Cursor getCursor() { toolkit.lockAWT(); try { return + * Component.this.getCursor(); } finally { toolkit.unlockAWT(); } } public + * FontMetrics getFontMetrics(Font f) { toolkit.lockAWT(); try { return + * Component.this.getFontMetrics(f); } finally { toolkit.unlockAWT(); } } + * public Color getForeground() { toolkit.lockAWT(); try { return + * Component.this.getForeground(); } finally { toolkit.unlockAWT(); } } + * public Point getLocation() { toolkit.lockAWT(); try { return + * Component.this.getLocation(); } finally { toolkit.unlockAWT(); } } public + * Point getLocationOnScreen() { toolkit.lockAWT(); try { return + * Component.this.getLocationOnScreen(); } finally { toolkit.unlockAWT(); } + * } public Dimension getSize() { toolkit.lockAWT(); try { return + * Component.this.getSize(); } finally { toolkit.unlockAWT(); } } public + * boolean isEnabled() { toolkit.lockAWT(); try { return + * Component.this.isEnabled(); } finally { toolkit.unlockAWT(); } } public + * boolean isFocusTraversable() { toolkit.lockAWT(); try { return + * Component.this.isFocusTraversable(); } finally { toolkit.unlockAWT(); } } + * public boolean isShowing() { toolkit.lockAWT(); try { return + * Component.this.isShowing(); } finally { toolkit.unlockAWT(); } } public + * boolean isVisible() { toolkit.lockAWT(); try { return + * Component.this.isVisible(); } finally { toolkit.unlockAWT(); } } public + * void removeFocusListener(FocusListener l) { + * Component.this.removeFocusListener(l); } + * @Override public void removePropertyChangeListener(PropertyChangeListener + * listener) { toolkit.lockAWT(); try { + * super.removePropertyChangeListener(listener); listenersCount--; if + * (listenersCount > 0) { return; } // if there are no more listeners, + * remove handlers: + * Component.this.removeFocusListener(accessibleAWTFocusHandler); + * Component.this.removeComponentListener(accessibleAWTComponentHandler); + * accessibleAWTComponentHandler = null; accessibleAWTFocusHandler = null; } + * finally { toolkit.unlockAWT(); } } public void requestFocus() { + * toolkit.lockAWT(); try { Component.this.requestFocus(); } finally { + * toolkit.unlockAWT(); } } public void setBackground(Color color) { + * toolkit.lockAWT(); try { Component.this.setBackground(color); } finally { + * toolkit.unlockAWT(); } } public void setBounds(Rectangle r) { + * toolkit.lockAWT(); try { Component.this.setBounds(r); } finally { + * toolkit.unlockAWT(); } } public void setCursor(Cursor cursor) { + * toolkit.lockAWT(); try { Component.this.setCursor(cursor); } finally { + * toolkit.unlockAWT(); } } public void setEnabled(boolean enabled) { + * toolkit.lockAWT(); try { Component.this.setEnabled(enabled); } finally { + * toolkit.unlockAWT(); } } public void setFont(Font f) { toolkit.lockAWT(); + * try { Component.this.setFont(f); } finally { toolkit.unlockAWT(); } } + * public void setForeground(Color color) { toolkit.lockAWT(); try { + * Component.this.setForeground(color); } finally { toolkit.unlockAWT(); } } + * public void setLocation(Point p) { toolkit.lockAWT(); try { + * Component.this.setLocation(p); } finally { toolkit.unlockAWT(); } } + * public void setSize(Dimension size) { toolkit.lockAWT(); try { + * Component.this.setSize(size); } finally { toolkit.unlockAWT(); } } public + * void setVisible(boolean visible) { toolkit.lockAWT(); try { + * Component.this.setVisible(visible); } finally { toolkit.unlockAWT(); } } + * @Override public Accessible getAccessibleParent() { toolkit.lockAWT(); + * try { Accessible aParent = super.getAccessibleParent(); if (aParent != + * null) { return aParent; } Container parent = getParent(); return (parent + * instanceof Accessible ? (Accessible) parent : null); } finally { + * toolkit.unlockAWT(); } } + * @Override public Accessible getAccessibleChild(int i) { + * toolkit.lockAWT(); try { return null; } finally { toolkit.unlockAWT(); } + * } + * @Override public int getAccessibleChildrenCount() { toolkit.lockAWT(); + * try { return 0; } finally { toolkit.unlockAWT(); } } + * @Override public AccessibleComponent getAccessibleComponent() { return + * this; } + * @Override public String getAccessibleDescription() { return + * super.getAccessibleDescription(); // why override? } + * @Override public int getAccessibleIndexInParent() { toolkit.lockAWT(); + * try { if (getAccessibleParent() == null) { return -1; } int count = 0; + * Container parent = getParent(); for (int i = 0; i < + * parent.getComponentCount(); i++) { Component aComp = + * parent.getComponent(i); if (aComp instanceof Accessible) { if (aComp == + * Component.this) { return count; } ++count; } } return -1; } finally { + * toolkit.unlockAWT(); } } + * @Override public AccessibleRole getAccessibleRole() { toolkit.lockAWT(); + * try { return AccessibleRole.AWT_COMPONENT; } finally { + * toolkit.unlockAWT(); } } + * @Override public AccessibleStateSet getAccessibleStateSet() { + * toolkit.lockAWT(); try { AccessibleStateSet set = new + * AccessibleStateSet(); if (isEnabled()) { + * set.add(AccessibleState.ENABLED); } if (isFocusable()) { + * set.add(AccessibleState.FOCUSABLE); } if (hasFocus()) { + * set.add(AccessibleState.FOCUSED); } if (isOpaque()) { + * set.add(AccessibleState.OPAQUE); } if (isShowing()) { + * set.add(AccessibleState.SHOWING); } if (isVisible()) { + * set.add(AccessibleState.VISIBLE); } return set; } finally { + * toolkit.unlockAWT(); } } + * @Override public Locale getLocale() throws IllegalComponentStateException + * { toolkit.lockAWT(); try { return Component.this.getLocale(); } finally { + * toolkit.unlockAWT(); } } } + */ + + /** + * The BltBufferStrategy class provides opportunity of blitting offscreen + * surfaces to a component. For more information on blitting, see Bit blit. + * + * @since Android 1.0 + */ + protected class BltBufferStrategy extends BufferStrategy { + + /** + * The back buffers. + */ + protected VolatileImage[] backBuffers; + + /** + * The caps. + */ + protected BufferCapabilities caps; + + /** + * The width. + */ + protected int width; + + /** + * The height. + */ + protected int height; + + /** + * The validated contents. + */ + protected boolean validatedContents; + + /** + * Instantiates a new BltBufferStrategy buffer strategy. + * + * @param numBuffers + * the number of buffers. + * @param caps + * the BufferCapabilities. + * @throws NotImplementedException + * the not implemented exception. + */ + protected BltBufferStrategy(int numBuffers, BufferCapabilities caps) + throws org.apache.harmony.luni.util.NotImplementedException { + if (true) { + throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$ + } + } + + /** + * Returns true if the drawing buffer has been lost since the last call + * to getDrawGraphics. + * + * @return true if the drawing buffer has been lost since the last call + * to getDrawGraphics, false otherwise. + * @see java.awt.image.BufferStrategy#contentsLost() + */ + @Override + public boolean contentsLost() { + if (true) { + throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$ + } + return false; + } + + /** + * Returns true if the drawing buffer has been restored from a lost + * state and reinitialized to the default background color. + * + * @return true if the drawing buffer has been restored from a lost + * state and reinitialized to the default background color, + * false otherwise. + * @see java.awt.image.BufferStrategy#contentsRestored() + */ + @Override + public boolean contentsRestored() { + if (true) { + throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$ + } + return false; + } + + /** + * Creates the back buffers. + * + * @param numBuffers + * the number of buffers. + */ + protected void createBackBuffers(int numBuffers) { + if (true) { + throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$ + } + } + + /** + * Returns the BufferCapabilities of the buffer strategy. + * + * @return the BufferCapabilities. + * @see java.awt.image.BufferStrategy#getCapabilities() + */ + @Override + public BufferCapabilities getCapabilities() { + return (BufferCapabilities)caps.clone(); + } + + /** + * Gets Graphics of current buffer strategy. + * + * @return the Graphics of current buffer strategy. + * @see java.awt.image.BufferStrategy#getDrawGraphics() + */ + @Override + public Graphics getDrawGraphics() { + if (true) { + throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$ + } + return null; + } + + /** + * Revalidates the lost drawing buffer. + */ + protected void revalidate() { + if (true) { + throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$ + } + } + + /** + * Shows the next available buffer. + * + * @see java.awt.image.BufferStrategy#show() + */ + @Override + public void show() { + if (true) { + throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$ + } + } + } + + /** + * The FlipBufferStrategy class is for flipping buffers on a component. + * + * @since Android 1.0 + */ + protected class FlipBufferStrategy extends BufferStrategy { + + /** + * The Buffer Capabilities. + */ + protected BufferCapabilities caps; + + /** + * The drawing buffer. + */ + protected Image drawBuffer; + + /** + * The drawing VolatileImage buffer. + */ + protected VolatileImage drawVBuffer; + + /** + * The number of buffers. + */ + protected int numBuffers; + + /** + * The validated contents indicates if the drawing buffer is restored + * from lost state. + */ + protected boolean validatedContents; + + /** + * Instantiates a new flip buffer strategy. + * + * @param numBuffers + * the number of buffers. + * @param caps + * the BufferCapabilities. + * @throws AWTException + * if the capabilities supplied could not be supported or + * met. + */ + protected FlipBufferStrategy(int numBuffers, BufferCapabilities caps) throws AWTException { + // ???AWT + /* + * if (!(Component.this instanceof Window) && !(Component.this + * instanceof Canvas)) { // awt.14B=Only Canvas or Window is allowed + * throw new ClassCastException(Messages.getString("awt.14B")); + * //$NON-NLS-1$ } + */ + // TODO: throw new AWTException("Capabilities are not supported"); + this.numBuffers = numBuffers; + this.caps = (BufferCapabilities)caps.clone(); + } + + /** + * Returns true if the drawing buffer has been lost since the last call + * to getDrawGraphics. + * + * @return true if the drawing buffer has been lost since the last call + * to getDrawGraphics, false otherwise. + * @see java.awt.image.BufferStrategy#contentsLost() + */ + @Override + public boolean contentsLost() { + if (true) { + throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$ + } + return false; + } + + /** + * Returns true if the drawing buffer has been restored from a lost + * state and reinitialized to the default background color. + * + * @return true if the drawing buffer has been restored from a lost + * state and reinitialized to the default background color, + * false otherwise. + * @see java.awt.image.BufferStrategy#contentsRestored() + */ + @Override + public boolean contentsRestored() { + if (true) { + throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$ + } + return false; + } + + /** + * Creates flipping buffers with the specified buffer capabilities. + * + * @param numBuffers + * the number of buffers. + * @param caps + * the BufferCapabilities. + * @throws AWTException + * if the capabilities could not be supported or met. + */ + protected void createBuffers(int numBuffers, BufferCapabilities caps) throws AWTException { + if (numBuffers < 2) { + // awt.14C=Number of buffers must be greater than one + throw new IllegalArgumentException(Messages.getString("awt.14C")); //$NON-NLS-1$ + } + if (!caps.isPageFlipping()) { + // awt.14D=Buffer capabilities should support flipping + throw new IllegalArgumentException(Messages.getString("awt.14D")); //$NON-NLS-1$ + } + if (!Component.this.behaviour.isDisplayable()) { + // awt.14E=Component should be displayable + throw new IllegalStateException(Messages.getString("awt.14E")); //$NON-NLS-1$ + } + // TODO: throw new AWTException("Capabilities are not supported"); + if (true) { + throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$ + } + } + + /** + * Destroy buffers. + */ + protected void destroyBuffers() { + if (true) { + throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$ + } + } + + /** + * Flips the contents of the back buffer to the front buffer. + * + * @param flipAction + * the flip action. + */ + protected void flip(BufferCapabilities.FlipContents flipAction) { + if (true) { + throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$ + } + } + + /** + * Gets the back buffer as Image. + * + * @return the back buffer as Image. + */ + protected Image getBackBuffer() { + if (true) { + throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$ + } + return null; + } + + /** + * Returns the BufferCapabilities of the buffer strategy. + * + * @return the BufferCapabilities. + * @see java.awt.image.BufferStrategy#getCapabilities() + */ + @Override + public BufferCapabilities getCapabilities() { + return (BufferCapabilities)caps.clone(); + } + + /** + * Gets Graphics of current buffer strategy. + * + * @return the Graphics of current buffer strategy. + * @see java.awt.image.BufferStrategy#getDrawGraphics() + */ + @Override + public Graphics getDrawGraphics() { + if (true) { + throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$ + } + return null; + } + + /** + * Revalidates the lost drawing buffer. + */ + protected void revalidate() { + if (true) { + throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$ + } + } + + /** + * Shows the next available buffer. + * + * @see java.awt.image.BufferStrategy#show() + */ + @Override + public void show() { + if (true) { + throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$ + } + } + } + + /** + * The internal component's state utilized by the visual theme. + */ + class ComponentState implements State { + + /** + * The default minimum size. + */ + private Dimension defaultMinimumSize = new Dimension(); + + /** + * Checks if the component is enabled. + * + * @return true, if the component is enabled. + */ + public boolean isEnabled() { + return enabled; + } + + /** + * Checks if the component is visible. + * + * @return true, if the component is visible. + */ + public boolean isVisible() { + return visible; + } + + /** + * Checks if is focused. + * + * @return true, if is focused. + */ + public boolean isFocused() { + // ???AWT: return isFocusOwner(); + return false; + } + + /** + * Gets the font. + * + * @return the font. + */ + public Font getFont() { + return Component.this.getFont(); + } + + /** + * Checks if the font has been set. + * + * @return true, if the font has been set. + */ + public boolean isFontSet() { + return font != null; + } + + /** + * Gets the background color. + * + * @return the background color. + */ + public Color getBackground() { + Color c = Component.this.getBackground(); + return (c != null) ? c : getDefaultBackground(); + } + + /** + * Checks if the background is set. + * + * @return true, if the background is set. + */ + public boolean isBackgroundSet() { + return backColor != null; + } + + /** + * Gets the text color. + * + * @return the text color. + */ + public Color getTextColor() { + Color c = getForeground(); + return (c != null) ? c : getDefaultForeground(); + } + + /** + * Checks if the text color is set. + * + * @return true, if the text color is set. + */ + public boolean isTextColorSet() { + return foreColor != null; + } + + /** + * Gets the font metrics. + * + * @return the font metrics. + */ + @SuppressWarnings("deprecation") + public FontMetrics getFontMetrics() { + return toolkit.getFontMetrics(Component.this.getFont()); + } + + /** + * Gets the bounding rectangle. + * + * @return the bounding rectangle. + */ + public Rectangle getBounds() { + return new Rectangle(x, y, w, h); + } + + /** + * Gets the size of the bounding rectangle. + * + * @return the size of the bounding rectangle. + */ + public Dimension getSize() { + return new Dimension(w, h); + } + + /** + * Gets the window id. + * + * @return the window id. + */ + public long getWindowId() { + NativeWindow win = getNativeWindow(); + return (win != null) ? win.getId() : 0; + } + + /** + * Gets the default minimum size. + * + * @return the default minimum size. + */ + public Dimension getDefaultMinimumSize() { + if (defaultMinimumSize == null) { + calculate(); + } + return defaultMinimumSize; + } + + /** + * Sets the default minimum size. + * + * @param size + * the new default minimum size. + */ + public void setDefaultMinimumSize(Dimension size) { + defaultMinimumSize = size; + } + + /** + * Reset the default minimum size to null. + */ + public void reset() { + defaultMinimumSize = null; + } + + /** + * Calculate the default minimum size: to be overridden. + */ + public void calculate() { + // to be overridden + } + } + + // ???AWT: + // protected transient AccessibleContext accessibleContext; + + /** + * The behaviour. + */ + final transient ComponentBehavior behaviour; + + // ???AWT: + public Container parent; + + /** + * The name. + */ + private String name; + + /** + * The auto name. + */ + private boolean autoName = true; + + /** + * The font. + */ + private Font font; + + /** + * The back color. + */ + private Color backColor; + + /** + * The fore color. + */ + private Color foreColor; + + /** + * The deprecated event handler. + */ + boolean deprecatedEventHandler = true; + + /** + * The enabled events. + */ + private long enabledEvents; + + /** + * The enabled AWT events. + */ + private long enabledAWTEvents; + + /** + * The component listeners. + */ + private final AWTListenerList componentListeners = new AWTListenerList( + this); + + /** + * The focus listeners. + */ + private final AWTListenerList focusListeners = new AWTListenerList( + this); + + /** + * The hierarchy listeners. + */ + private final AWTListenerList hierarchyListeners = new AWTListenerList( + this); + + /** + * The hierarchy bounds listeners. + */ + private final AWTListenerList hierarchyBoundsListeners = new AWTListenerList( + this); + + /** + * The key listeners. + */ + private final AWTListenerList keyListeners = new AWTListenerList(this); + + /** + * The mouse listeners. + */ + private final AWTListenerList mouseListeners = new AWTListenerList( + this); + + /** + * The mouse motion listeners. + */ + private final AWTListenerList mouseMotionListeners = new AWTListenerList( + this); + + /** + * The mouse wheel listeners. + */ + private final AWTListenerList mouseWheelListeners = new AWTListenerList( + this); + + /** + * The input method listeners. + */ + private final AWTListenerList inputMethodListeners = new AWTListenerList( + this); + + /** + * The x. + */ int x; + + /** + * The y. + */ int y; - int w = 0; - int h = 0; - - protected boolean enabled = true; - private boolean inputMethodsEnabled = true; - transient boolean dispatchToIM = true; - private boolean focusable = true; // By default, all Components return - boolean visible = true; - private boolean wasShowing; - private boolean wasDisplayable; - private boolean valid; - private Dimension defaultMinimumSize; - private ComponentOrientation orientation; - private PropertyChangeSupport propertyChangeSupport; - private Dimension maximumSize; + + /** + * The w. + */ + int w; + + /** + * The h. + */ + int h; + + /** + * The maximum size. + */ + private Dimension maximumSize; + + /** + * The minimum size. + */ private Dimension minimumSize; - private Dimension preferredSize; - private Color backColor = Color.WHITE; - private Color foreColor = Color.BLACK; + + /** + * The preferred size. + */ + private Dimension preferredSize; + + /** + * The bounds mask param. + */ + private int boundsMaskParam; + + /** + * The ignore repaint. + */ + private boolean ignoreRepaint; + + /** + * The enabled. + */ + private boolean enabled = true; + + /** + * The input methods enabled. + */ + private boolean inputMethodsEnabled = true; + + /** + * The dispatch to im. + */ + transient boolean dispatchToIM = true; + + /** + * The focusable. + */ + private boolean focusable = true; // By default, all Components return + + // true from isFocusable() method + /** + * The visible. + */ + boolean visible = true; + + /** + * The called set focusable. + */ + private boolean calledSetFocusable; + + /** + * The overridden is focusable. + */ + private boolean overridenIsFocusable = true; + + /** + * The focus traversal keys enabled. + */ + private boolean focusTraversalKeysEnabled = true; + + /** + * Possible keys are: FORWARD_TRAVERSAL_KEYS, BACKWARD_TRAVERSAL_KEYS, + * UP_CYCLE_TRAVERSAL_KEYS. + */ + private final Map> traversalKeys = new HashMap>(); + + /** + * The traversal i ds. + */ + int[] traversalIDs; + + /** + * The locale. + */ + private Locale locale; + + /** + * The orientation. + */ + private ComponentOrientation orientation; + + /** + * The property change support. + */ + private PropertyChangeSupport propertyChangeSupport; + + // ???AWT: private ArrayList popups; + + /** + * The coalescer. + */ + private boolean coalescer; + + /** + * The events table. + */ + private Hashtable> eventsTable; + + /** + * Cashed reference used during EventQueue.postEvent() + */ + private LinkedList eventsList; + + /** + * The hierarchy changing counter. + */ + private int hierarchyChangingCounter; + + /** + * The was showing. + */ + private boolean wasShowing; + + /** + * The was displayable. + */ + private boolean wasDisplayable; + + /** + * The cursor. + */ + Cursor cursor; + + // ???AWT: DropTarget dropTarget; + + /** + * The mouse exited expected. + */ + private boolean mouseExitedExpected; + + /** + * The repaint region. + */ + transient MultiRectArea repaintRegion; + + // ???AWT: transient RedrawManager redrawManager; + /** + * The redraw manager. + */ + transient Object redrawManager; + + /** + * The valid. + */ + private boolean valid; + + /** + * The updated images. + */ + private HashMap updatedImages; + + /** + * The lock object for private component's data which don't affect the + * component hierarchy. + */ + private class ComponentLock { + } + + /** + * The component lock. + */ + private final transient Object componentLock = new ComponentLock(); + static { + PrivilegedAction action = new PrivilegedAction() { + public String[] run() { + String properties[] = new String[2]; + properties[0] = System.getProperty("awt.image.redrawrate", "100"); //$NON-NLS-1$ //$NON-NLS-2$ + properties[1] = System.getProperty("awt.image.incrementaldraw", "true"); //$NON-NLS-1$ //$NON-NLS-2$ + return properties; + } + }; + String properties[] = AccessController.doPrivileged(action); + // FIXME: rate is never used, can this code and the get property above + // be removed? + // int rate; + // + // try { + // rate = Integer.decode(properties[0]).intValue(); + // } catch (NumberFormatException e) { + // rate = 100; + // } + incrementalImageUpdate = properties[1].equals("true"); //$NON-NLS-1$ + } + + /** + * Instantiates a new component. + */ + protected Component() { + toolkit.lockAWT(); + try { + orientation = ComponentOrientation.UNKNOWN; + redrawManager = null; + // ???AWT + /* + traversalIDs = this instanceof Container ? + KeyboardFocusManager.contTraversalIDs : + KeyboardFocusManager.compTraversalIDs; for (int element : + traversalIDs) { traversalKeys.put(new Integer(element), null); } + */ + behaviour = createBehavior(); + + // behaviour = null; + + deriveCoalescerFlag(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Determine that the class inherited from Component declares the method + * coalesceEvents(), and put the results to the childClassesFlags map. + */ + private void deriveCoalescerFlag() { + Class thisClass = getClass(); + boolean flag = true; + synchronized (childClassesFlags) { + Boolean flagWrapper = childClassesFlags.get(thisClass); + if (flagWrapper == null) { + Method coalesceMethod = null; + for (Class c = thisClass; c != Component.class; c = c.getSuperclass()) { + try { + coalesceMethod = c.getDeclaredMethod("coalesceEvents", new Class[] { //$NON-NLS-1$ + Class.forName("java.awt.AWTEvent"), //$NON-NLS-1$ + Class.forName("java.awt.AWTEvent")}); //$NON-NLS-1$ + } catch (Exception e) { + } + if (coalesceMethod != null) { + break; + } + } + flag = (coalesceMethod != null); + childClassesFlags.put(thisClass, Boolean.valueOf(flag)); + } else { + flag = flagWrapper.booleanValue(); + } + } + coalescer = flag; + if (flag) { + eventsTable = new Hashtable>(); + } else { + eventsTable = null; + } + } + + /** + * Sets the name of the Component. + * + * @param name + * the new name of the Component. + */ + public void setName(String name) { + String oldName; + toolkit.lockAWT(); + try { + autoName = false; + oldName = this.name; + this.name = name; + } finally { + toolkit.unlockAWT(); + } + firePropertyChange("name", oldName, name); //$NON-NLS-1$ + } + + /** + * Gets the name of this Component. + * + * @return the name of this Component. + */ + public String getName() { + toolkit.lockAWT(); + try { + if ((name == null) && autoName) { + name = autoName(); + } + return name; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Auto name. + * + * @return the string. + */ + String autoName() { + String name = getClass().getName(); + if (name.indexOf("$") != -1) { //$NON-NLS-1$ + return null; + } + // ???AWT + // int number = toolkit.autoNumber.nextComponent++; + int number = 0; + name = name.substring(name.lastIndexOf(".") + 1) + Integer.toString(number); //$NON-NLS-1$ + return name; + } + + /** + * Returns the string representation of the Component. + * + * @return the string representation of the Component. + */ + @Override + public String toString() { + /* + * The format is based on 1.5 release behavior which can be revealed by + * the following code: Component c = new Component(){}; + * c.setVisible(false); System.out.println(c); + */ + toolkit.lockAWT(); + try { + return getClass().getName() + "[" + paramString() + "]"; //$NON-NLS-1$ //$NON-NLS-2$ + } finally { + toolkit.unlockAWT(); + } + } + + // ???AWT + /* + * public void add(PopupMenu popup) { toolkit.lockAWT(); try { if + * (popup.getParent() == this) { return; } if (popups == null) { popups = + * new ArrayList(); } popup.setParent(this); popups.add(popup); } + * finally { toolkit.unlockAWT(); } } + */ + + /** + * Returns true, if the component contains the specified Point. + * + * @param p + * the Point. + * @return true, if the component contains the specified Point, false + * otherwise. + */ + public boolean contains(Point p) { + toolkit.lockAWT(); + try { + return contains(p.x, p.y); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Returns true, if the component contains the point with the specified + * coordinates. + * + * @param x + * the x coordinate. + * @param y + * the y coordinate. + * @return true, if the component contains the point with the specified + * coordinates, false otherwise. + */ + public boolean contains(int x, int y) { + toolkit.lockAWT(); + try { + return inside(x, y); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Deprecated: replaced by replaced by getSize() method. + * + * @return the dimension. + * @deprecated Replaced by getSize() method. + */ + @Deprecated + public Dimension size() { + toolkit.lockAWT(); + try { + return new Dimension(w, h); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Returns the baseline. The baseline is measured from the top of + * the component. This method is primarily meant for + * LayoutManagers to align components along their + * baseline. A return value less than 0 indicates this component + * does not have a reasonable baseline and that + * LayoutManagers should not align this component on + * its baseline. + *

+ * The default implementation returns -1. Subclasses that support + * baseline should override appropriately. If a value >= 0 is + * returned, then the component has a valid baseline for any + * size >= the minimum size and getBaselineResizeBehavior + * can be used to determine how the baseline changes with size. + * + * @param width the width to get the baseline for + * @param height the height to get the baseline for + * @return the baseline or < 0 indicating there is no reasonable + * baseline + * @throws IllegalArgumentException if width or height is < 0 + * @see #getBaselineResizeBehavior + * @see java.awt.FontMetrics + * @since 1.6 + */ + public int getBaseline(int width, int height) { + if (width < 0 || height < 0) { + throw new IllegalArgumentException( + "Width and height must be >= 0"); + } + return -1; + } - public Container parent = null; - - private int boundsMaskParam = 0; - private Cursor cursor; - - private Font font; - - private boolean calledSetFocusable; - - public Cursor getCursor() { - if (cursor != null) { - return cursor; - // ???AWT - } else if (parent != null) { - return parent.getCursor(); + // ???AWT + public Container getParent() { + toolkit.lockAWT(); + try { + return parent; + } finally { + toolkit.unlockAWT(); } - return Cursor.getDefaultCursor(); - } + } + + /** + * List. + * + * @param out + * the out. + * @param indent + * the indent + * @return the nearest heavyweight ancestor in hierarchy or + * null if not found. + */ + // ???AWT + Component getHWAncestor() { + return (parent != null ? parent.getHWSurface() : null); + } + + /** + * @return heavyweight component that is equal to or is a nearest + * heavyweight container of the current component, or + * null if not found. + */ + // ???AWT + Component getHWSurface() { + Component parent; + for (parent = this; (parent != null) && (parent.isLightweight()); parent = parent.getParent()) { ; } + return parent; + } + Window getWindowAncestor() { + Component par; for (par = this; par != null && !(par instanceof Window); par = par.getParent()) { ; } + return (Window) par; + } + + /** + * To be called by container + */ + // ???AWT + + void setParent(Container parent) { + this.parent = parent; + setRedrawManager(); + } - public void setCursor(Cursor cursor) { - this.cursor = cursor; - setCursor(); + void setRedrawManager() { + // redrawManager = getRedrawManager(); + } + + public void remove(MenuComponent menu) { + toolkit.lockAWT(); + try { + if (menu.getParent() == this) { + menu.setParent(null); + // popups.remove(menu); + } + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Prints a list of this component with the specified number of leading + * whitespace characters to the specified PrintStream. + * + * @param out + * the output PrintStream object. + * @param indent + * how many leading whitespace characters to prepend. + */ + public void list(PrintStream out, int indent) { + toolkit.lockAWT(); + try { + out.println(getIndentStr(indent) + this); + } finally { + toolkit.unlockAWT(); + } } + /** + * Prints a list of this component to the specified PrintWriter. + * + * @param out + * the output PrintWriter object. + */ + public void list(PrintWriter out) { + toolkit.lockAWT(); + try { + list(out, 1); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Prints a list of this component with the specified number of leading + * whitespace characters to the specified PrintWriter. + * + * @param out + * the output PrintWriter object. + * @param indent + * how many leading whitespace characters to prepend. + */ + public void list(PrintWriter out, int indent) { + toolkit.lockAWT(); + try { + out.println(getIndentStr(indent) + this); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets a string composed of the desired number of whitespace characters. + * + * @param indent + * the length of the String to return. + * @return the string composed of the desired number of whitespace + * characters. + */ + String getIndentStr(int indent) { + char[] ind = new char[indent]; + for (int i = 0; i < indent; ind[i++] = ' ') { + ; + } + return new String(ind); + } + + /** + * Prints a list of this component to the specified PrintStream. + * + * @param out + * the output PrintStream object. + */ + public void list(PrintStream out) { + toolkit.lockAWT(); + try { + // default indent = 1 + list(out, 1); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Prints a list of this component to the standard system output stream. + */ + public void list() { + toolkit.lockAWT(); + try { + list(System.out); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Prints this component. + * + * @param g + * the Graphics to be used for painting. + */ + public void print(Graphics g) { + toolkit.lockAWT(); + try { + paint(g); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Prints the component and all of its subcomponents. + * + * @param g + * the Graphics to be used for painting. + */ + public void printAll(Graphics g) { + toolkit.lockAWT(); + try { + paintAll(g); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Sets the size of the Component specified by width and height parameters. + * + * @param width + * the width of the Component. + * @param height + * the height of the Component. + */ + public void setSize(int width, int height) { + toolkit.lockAWT(); + try { + resize(width, height); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Sets the size of the Component specified by Dimension object. + * + * @param d + * the new size of the Component. + */ + public void setSize(Dimension d) { + toolkit.lockAWT(); + try { + resize(d); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Deprecated: replaced by setSize(int, int) method. + * + * @param width + * the width. + * @param height + * the height. + * @deprecated Replaced by setSize(int, int) method. + */ + @Deprecated + public void resize(int width, int height) { + toolkit.lockAWT(); + try { + boundsMaskParam = NativeWindow.BOUNDS_NOMOVE; + setBounds(x, y, width, height); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Deprecated: replaced by setSize(int, int) method. + * + * @param size + * the size. + * @deprecated Replaced by setSize(int, int) method. + */ + @Deprecated + public void resize(Dimension size) { + toolkit.lockAWT(); + try { + setSize(size.width, size.height); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Checks whether or not this component is completely opaque. + * + * @return true, if this component is completely opaque, false by default. + */ + public boolean isOpaque() { + toolkit.lockAWT(); + try { + return behaviour.isOpaque(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Disables. + * + * @deprecated Replaced by setEnabled(boolean) method. + */ + @Deprecated + public void disable() { + toolkit.lockAWT(); + try { + setEnabledImpl(false); + } finally { + toolkit.unlockAWT(); + } + // ???AWT: fireAccessibleStateChange(AccessibleState.ENABLED, false); + } + + /** + * Enables this component. + * + * @deprecated Replaced by setEnabled(boolean) method. + */ + @Deprecated + public void enable() { + toolkit.lockAWT(); + try { + setEnabledImpl(true); + } finally { + toolkit.unlockAWT(); + } + // ???AWT: fireAccessibleStateChange(AccessibleState.ENABLED, true); + } + + /** + * Enables or disable this component. + * + * @param b + * the boolean parameter. + * @deprecated Replaced by setEnabled(boolean) method. + */ + @Deprecated + public void enable(boolean b) { + toolkit.lockAWT(); + try { + if (b) { + enable(); + } else { + disable(); + } + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Stores the location of this component to the specified Point object; + * returns the point of the component's top-left corner. + * + * @param rv + * the Point object where the component's top-left corner + * position will be stored. + * @return the Point which specifies the component's top-left corner. + */ + public Point getLocation(Point rv) { + toolkit.lockAWT(); + try { + if (rv == null) { + rv = new Point(); + } + rv.setLocation(getX(), getY()); + return rv; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the location of this component on the form; returns the point of the + * component's top-left corner. + * + * @return the Point which specifies the component's top-left corner. + */ + public Point getLocation() { + toolkit.lockAWT(); + try { + return location(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the size of this Component. + * + * @return the size of this Component. + */ + public Dimension getSize() { + toolkit.lockAWT(); + try { + return size(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Stores the size of this Component to the specified Dimension object. + * + * @param rv + * the Dimension object where the size of the Component will be + * stored. + * @return the Dimension of this Component. + */ + public Dimension getSize(Dimension rv) { + toolkit.lockAWT(); + try { + if (rv == null) { + rv = new Dimension(); + } + rv.setSize(getWidth(), getHeight()); + return rv; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Checks whether or not this Component is valid. A component is valid if it + * is correctly sized and positioned within its parent container and all its + * children are also valid. + * + * @return true, if the Component is valid, false otherwise. + */ + public boolean isValid() { + toolkit.lockAWT(); + try { + return valid && behaviour.isDisplayable(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Deprecated: replaced by getComponentAt(int, int) method. + * + * @return the Point. + * @deprecated Replaced by getComponentAt(int, int) method. + */ + @Deprecated + public Point location() { + toolkit.lockAWT(); + try { + return new Point(x, y); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Connects this Component to a native screen resource and makes it + * displayable. This method not be called directly by user applications. + */ + public void addNotify() { + toolkit.lockAWT(); + try { + prepare4HierarchyChange(); + behaviour.addNotify(); + // ???AWT + // finishHierarchyChange(this, parent, 0); + // if (dropTarget != null) { + // dropTarget.addNotify(peer); + // } + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Map to display. + * + * @param b + * the b. + */ + void mapToDisplay(boolean b) { + // ???AWT + /* + * if (b && !isDisplayable()) { if ((this instanceof Window) || ((parent + * != null) && parent.isDisplayable())) { addNotify(); } } else if (!b + * && isDisplayable()) { removeNotify(); } + */ + } + + /** + * Gets the toolkit. + * + * @return accessible context specific for particular component. + */ + // ???AWT + /* + * AccessibleContext createAccessibleContext() { return null; } public + * AccessibleContext getAccessibleContext() { toolkit.lockAWT(); try { if + * (accessibleContext == null) { accessibleContext = + * createAccessibleContext(); } return accessibleContext; } finally { + * toolkit.unlockAWT(); } } + */ + + /** + * Gets Toolkit for the current Component. + * + * @return the Toolkit of this Component. + */ + public Toolkit getToolkit() { + return toolkit; + } + + /** + * Gets this component's locking object for AWT component tree and layout + * operations. + * + * @return the tree locking object. + */ + public final Object getTreeLock() { + return toolkit.awtTreeLock; + } + + /** + * Handles the event. Use ActionListener instead of this. + * + * @param evt + * the Event. + * @param what + * the event's key. + * @return true, if successful. + * @deprecated Use ActionListener class for registering event listener. + */ + @Deprecated + public boolean action(Event evt, Object what) { + // to be overridden: do nothing, + // just return false to propagate event up to the parent container + return false; + } + + /** + * Gets the property change support. + * + * @return the property change support. + */ + private PropertyChangeSupport getPropertyChangeSupport() { + synchronized (componentLock) { + if (propertyChangeSupport == null) { + propertyChangeSupport = new PropertyChangeSupport(this); + } + return propertyChangeSupport; + } + } + + // ???AWT + /* + * public void addPropertyChangeListener(PropertyChangeListener listener) { + * getPropertyChangeSupport().addPropertyChangeListener(listener); } public + * void addPropertyChangeListener(String propertyName, + * PropertyChangeListener listener) { + * getPropertyChangeSupport().addPropertyChangeListener(propertyName, + * listener); } public void applyComponentOrientation(ComponentOrientation + * orientation) { toolkit.lockAWT(); try { + * setComponentOrientation(orientation); } finally { toolkit.unlockAWT(); } + * } + */ + + /** + * Returns true if the set of focus traversal keys for the given focus + * traversal operation has been explicitly defined for this Component. + * + * @param id + * the ID of traversal key. + * @return true, if the set of focus traversal keys for the given focus. + * traversal operation has been explicitly defined for this + * Component, false otherwise. + */ + public boolean areFocusTraversalKeysSet(int id) { + toolkit.lockAWT(); + try { + Integer Id = new Integer(id); + if (traversalKeys.containsKey(Id)) { + return traversalKeys.get(Id) != null; + } + // awt.14F=invalid focus traversal key identifier + throw new IllegalArgumentException(Messages.getString("awt.14F")); //$NON-NLS-1$ + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the bounds of the Component. + * + * @return the rectangle bounds of the Component. + * @deprecated Use getBounds() methood. + */ + @Deprecated + public Rectangle bounds() { + toolkit.lockAWT(); + try { + return new Rectangle(x, y, w, h); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Returns the construction status of a specified image with the specified + * width and height that is being created. + * + * @param image + * the image to be checked. + * @param width + * the width of scaled image which status is being checked, or + * -1. + * @param height + * the height of scaled image which status is being checked, or + * -1. + * @param observer + * the ImageObserver object to be notified while the image is + * being prepared. + * @return the ImageObserver flags of the current state of the image data. + */ + public int checkImage(Image image, int width, int height, ImageObserver observer) { + toolkit.lockAWT(); + try { + return toolkit.checkImage(image, width, height, observer); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Returns the construction status of a specified image that is being + * created. + * + * @param image + * the image to be checked. + * @param observer + * the ImageObserver object to be notified while the image is + * being prepared. + * @return the ImageObserver flags of the current state of the image data. + */ + public int checkImage(Image image, ImageObserver observer) { + toolkit.lockAWT(); + try { + return toolkit.checkImage(image, -1, -1, observer); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Coalesces the existed event with new event. + * + * @param existingEvent + * the existing event in the EventQueue. + * @param newEvent + * the new event to be posted to the EventQueue. + * @return the coalesced AWTEvent, or null if there is no coalescing done. + */ + protected AWTEvent coalesceEvents(AWTEvent existingEvent, AWTEvent newEvent) { + toolkit.lockAWT(); + try { + // Nothing to do: + // 1. Mouse events coalesced at WTK level + // 2. Paint events handled by RedrawManager + // This method is for overriding only + return null; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Checks if this Component is a coalescer. + * + * @return true, if is coalescer. + */ + boolean isCoalescer() { + return coalescer; + } + + /** + * Gets the relative event. + * + * @param id + * the id. + * @return the relative event. + */ + AWTEvent getRelativeEvent(int id) { + Integer idWrapper = new Integer(id); + eventsList = eventsTable.get(idWrapper); + if (eventsList == null) { + eventsList = new LinkedList(); + eventsTable.put(idWrapper, eventsList); + return null; + } + if (eventsList.isEmpty()) { + return null; + } + return eventsList.getLast(); + } + + /** + * Adds the new event. + * + * @param event + * the event. + */ + void addNewEvent(AWTEvent event) { + eventsList.addLast(event); + } + + /** + * Removes the relative event. + */ + void removeRelativeEvent() { + eventsList.removeLast(); + } + + /** + * Removes the next event. + * + * @param id + * the id. + */ + void removeNextEvent(int id) { + eventsTable.get(new Integer(id)).removeFirst(); + } + + /** + * Creates the image with the specified ImageProducer. + * + * @param producer + * the ImageProducer to be used for image creation. + * @return the image with the specified ImageProducer. + */ + public Image createImage(ImageProducer producer) { + toolkit.lockAWT(); + try { + return toolkit.createImage(producer); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Creates an off-screen drawable image to be used for double buffering. + * + * @param width + * the width of the image. + * @param height + * the height of the image. + * @return the off-screen drawable image or null if the component is not + * displayable or GraphicsEnvironment.isHeadless() method returns + * true. + */ + public Image createImage(int width, int height) { + toolkit.lockAWT(); + try { + if (!isDisplayable()) { + return null; + } + GraphicsConfiguration gc = getGraphicsConfiguration(); + if (gc == null) { + return null; + } + ColorModel cm = gc.getColorModel(Transparency.OPAQUE); + WritableRaster wr = cm.createCompatibleWritableRaster(width, height); + Image image = new BufferedImage(cm, wr, cm.isAlphaPremultiplied(), null); + fillImageBackground(image, width, height); + return image; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Creates an off-screen drawable image with the specified width, height and + * ImageCapabilities. + * + * @param width + * the width. + * @param height + * the height. + * @param caps + * the ImageCapabilities. + * @return the volatile image. + * @throws AWTException + * if an image with the specified capabilities cannot be + * created. + */ + public VolatileImage createVolatileImage(int width, int height, ImageCapabilities caps) + throws AWTException { + toolkit.lockAWT(); + try { + if (!isDisplayable()) { + return null; + } + GraphicsConfiguration gc = getGraphicsConfiguration(); + if (gc == null) { + return null; + } + VolatileImage image = gc.createCompatibleVolatileImage(width, height, caps); + fillImageBackground(image, width, height); + return image; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Creates a volatile off-screen drawable image which is used for double + * buffering. + * + * @param width + * the width of image. + * @param height + * the height of image. + * @return the volatile image a volatile off-screen drawable image which is + * used for double buffering or null if the component is not + * displayable, or GraphicsEnvironment.isHeadless() method returns + * true. + */ + public VolatileImage createVolatileImage(int width, int height) { + toolkit.lockAWT(); + try { + if (!isDisplayable()) { + return null; + } + GraphicsConfiguration gc = getGraphicsConfiguration(); + if (gc == null) { + return null; + } + VolatileImage image = gc.createCompatibleVolatileImage(width, height); + fillImageBackground(image, width, height); + return image; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Fill the image being created by createImage() or createVolatileImage() + * with the component's background color to prepare it for double-buffered + * painting. + * + * @param image + * the image. + * @param width + * the width. + * @param height + * the height. + */ + private void fillImageBackground(Image image, int width, int height) { + Graphics gr = image.getGraphics(); + gr.setColor(getBackground()); + gr.fillRect(0, 0, width, height); + gr.dispose(); + } + + /** + * Delivers event. + * + * @param evt + * the event. + * @deprecated Replaced by dispatchEvent(AWTEvent e) method. + */ + @Deprecated + public void deliverEvent(Event evt) { + postEvent(evt); + } + + /** + * Prompts the layout manager to lay out this component. + */ + public void doLayout() { + toolkit.lockAWT(); + try { + layout(); + } finally { + toolkit.unlockAWT(); + } + // Implemented in Container + } + + /** + * Fire property change impl. + * + * @param propertyName + * the property name. + * @param oldValue + * the old value. + * @param newValue + * the new value. + */ + private void firePropertyChangeImpl(String propertyName, Object oldValue, Object newValue) { + PropertyChangeSupport pcs; + synchronized (componentLock) { + if (propertyChangeSupport == null) { + return; + } + pcs = propertyChangeSupport; + } + pcs.firePropertyChange(propertyName, oldValue, newValue); + } + + /** + * Reports a bound property changes for int properties. + * + * @param propertyName + * the property name. + * @param oldValue + * the old property's value. + * @param newValue + * the new property's value. + */ + protected void firePropertyChange(String propertyName, int oldValue, int newValue) { + firePropertyChangeImpl(propertyName, new Integer(oldValue), new Integer(newValue)); + } + + /** + * Report a bound property change for a boolean-valued property. + * + * @param propertyName + * the property name. + * @param oldValue + * the property's old value. + * @param newValue + * the property's new value. + */ + protected void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) { + firePropertyChangeImpl(propertyName, Boolean.valueOf(oldValue), Boolean.valueOf(newValue)); + } + + /** + * Reports a bound property change for an Object-valued property. + * + * @param propertyName + * the property name. + * @param oldValue + * the property's old value. + * @param newValue + * the property's new value. + */ + protected void firePropertyChange(final String propertyName, final Object oldValue, + final Object newValue) { + firePropertyChangeImpl(propertyName, oldValue, newValue); + } + + /** + * Report a bound property change for a byte-valued property. + * + * @param propertyName + * the property name. + * @param oldValue + * the property's old value. + * @param newValue + * the property's new value. + */ + public void firePropertyChange(String propertyName, byte oldValue, byte newValue) { + firePropertyChangeImpl(propertyName, new Byte(oldValue), new Byte(newValue)); + } + + /** + * Report a bound property change for a char-valued property. + * + * @param propertyName + * the property name. + * @param oldValue + * the old property's value. + * @param newValue + * the new property's value. + */ + public void firePropertyChange(String propertyName, char oldValue, char newValue) { + firePropertyChangeImpl(propertyName, new Character(oldValue), new Character(newValue)); + } + + /** + * Report a bound property change for a short-valued property. + * + * @param propertyName + * the property name. + * @param oldValue + * the old property's value. + * @param newValue + * the new property's value. + */ + public void firePropertyChange(String propertyName, short oldValue, short newValue) { + firePropertyChangeImpl(propertyName, new Short(oldValue), new Short(newValue)); + } + + /** + * Report a bound property change for a long-valued property. + * + * @param propertyName + * the property name. + * @param oldValue + * the old property's value. + * @param newValue + * the new property's value. + */ + public void firePropertyChange(String propertyName, long oldValue, long newValue) { + firePropertyChangeImpl(propertyName, new Long(oldValue), new Long(newValue)); + } + + /** + * Report a bound property change for a float-valued property. + * + * @param propertyName + * the property name. + * @param oldValue + * the old property's value. + * @param newValue + * the new property's value. + */ + public void firePropertyChange(String propertyName, float oldValue, float newValue) { + firePropertyChangeImpl(propertyName, new Float(oldValue), new Float(newValue)); + } + + /** + * Report a bound property change for a double-valued property. + * + * @param propertyName + * the property name. + * @param oldValue + * the old property's value. + * @param newValue + * the new property's value. + */ + public void firePropertyChange(String propertyName, double oldValue, double newValue) { + firePropertyChangeImpl(propertyName, new Double(oldValue), new Double(newValue)); + } + + /** + * Gets the alignment along the x axis. + * + * @return the alignment along the x axis. + */ + public float getAlignmentX() { + toolkit.lockAWT(); + try { + return CENTER_ALIGNMENT; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the alignment along the y axis. + * + * @return the alignment along y axis. + */ + public float getAlignmentY() { + toolkit.lockAWT(); + try { + return CENTER_ALIGNMENT; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the background color for this component. + * + * @return the background color for this component. + */ + public Color getBackground() { + toolkit.lockAWT(); + try { + // ???AWT + /* + * if ((backColor == null) && (parent != null)) { return + * parent.getBackground(); } + */ + return backColor; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the bounding rectangle of this component. + * + * @return the bounding rectangle of this component. + */ + public Rectangle getBounds() { + toolkit.lockAWT(); + try { + return bounds(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Writes the data of the bounding rectangle to the specified Rectangle + * object. + * + * @param rv + * the Rectangle object where the bounding rectangle's data is + * stored. + * @return the bounding rectangle. + */ + public Rectangle getBounds(Rectangle rv) { + toolkit.lockAWT(); + try { + if (rv == null) { + rv = new Rectangle(); + } + rv.setBounds(x, y, w, h); + return rv; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the color model of the Component. + * + * @return the color model of the Component. + */ + public ColorModel getColorModel() { + toolkit.lockAWT(); + try { + return getToolkit().getColorModel(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the Component which contains the specified Point. + * + * @param p + * the Point. + * @return the Component which contains the specified Point. + */ + public Component getComponentAt(Point p) { + toolkit.lockAWT(); + try { + return getComponentAt(p.x, p.y); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the Component which contains the point with the specified + * coordinates. + * + * @param x + * the x coordinate of the point. + * @param y + * the y coordinate of the point. + * @return the Component which contains the point with the specified + * coordinates. + */ + public Component getComponentAt(int x, int y) { + toolkit.lockAWT(); + try { + return locate(x, y); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the component's orientation. + * + * @return the component's orientation. + */ + public ComponentOrientation getComponentOrientation() { + toolkit.lockAWT(); + try { + return orientation; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the cursor of the Component. + * + * @return the Cursor. + */ + public Cursor getCursor() { + toolkit.lockAWT(); + try { + if (cursor != null) { + return cursor; + // ???AWT + /* + * } else if (parent != null) { return parent.getCursor(); + */ + } + return Cursor.getDefaultCursor(); + } finally { + toolkit.unlockAWT(); + } + } + + // ???AWT + /* + * public DropTarget getDropTarget() { toolkit.lockAWT(); try { return + * dropTarget; } finally { toolkit.unlockAWT(); } } public Container + * getFocusCycleRootAncestor() { toolkit.lockAWT(); try { for (Container c = + * parent; c != null; c = c.getParent()) { if (c.isFocusCycleRoot()) { + * return c; } } return null; } finally { toolkit.unlockAWT(); } } + * @SuppressWarnings("unchecked") public Set + * getFocusTraversalKeys(int id) { toolkit.lockAWT(); try { Integer kId = + * new Integer(id); KeyboardFocusManager.checkTraversalKeysID(traversalKeys, + * kId); Set keys = traversalKeys.get(kId); if (keys + * == null && parent != null) { keys = parent.getFocusTraversalKeys(id); } + * if (keys == null) { keys = + * KeyboardFocusManager.getCurrentKeyboardFocusManager() + * .getDefaultFocusTraversalKeys(id); } return (Set) keys; } + * finally { toolkit.unlockAWT(); } } + */ + + /** + * Checks if the the focus traversal keys are enabled for this component. + * + * @return true, if the the focus traversal keys are enabled for this + * component, false otherwise. + */ + public boolean getFocusTraversalKeysEnabled() { + toolkit.lockAWT(); + try { + return focusTraversalKeysEnabled; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the font metrics of the specified Font. + * + * @param f + * the Font. + * @return the FontMetrics of the specified Font. + */ + @SuppressWarnings("deprecation") + public FontMetrics getFontMetrics(Font f) { + return toolkit.getFontMetrics(f); + } + + /** + * Gets the foreground color of the Component. + * + * @return the foreground color of the Component. + */ + public Color getForeground() { + toolkit.lockAWT(); + try { + // ???AWT + /* + * if (foreColor == null && parent != null) { return + * parent.getForeground(); } + */ + return foreColor; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the Graphics of the Component or null if this Component is not + * displayable. + * + * @return the Graphics of the Component or null if this Component is not + * displayable. + */ + public Graphics getGraphics() { + toolkit.lockAWT(); + try { + if (!isDisplayable()) { + return null; + } + Graphics g = behaviour.getGraphics(0, 0, w, h); + g.setColor(foreColor); + g.setFont(font); + return g; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the GraphicsConfiguration associated with this Component. + * + * @return the GraphicsConfiguration associated with this Component. + */ + public GraphicsConfiguration getGraphicsConfiguration() { + // ???AWT + /* + * toolkit.lockAWT(); try { Window win = getWindowAncestor(); if (win == + * null) { return null; } return win.getGraphicsConfiguration(); } + * finally { toolkit.unlockAWT(); } + */ + return null; + } + + /** + * Gets the height of the Component. + * + * @return the height of the Component. + */ + public int getHeight() { + toolkit.lockAWT(); + try { + return h; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Returns true if paint messages received from the operating system should + * be ignored. + * + * @return true if paint messages received from the operating system should + * be ignored, false otherwise. + */ + public boolean getIgnoreRepaint() { + toolkit.lockAWT(); + try { + return ignoreRepaint; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the input context of this component for handling the communication + * with input methods when text is entered in this component. + * + * @return the InputContext used by this Component or null if no context is + * specifined. + */ + public InputContext getInputContext() { + toolkit.lockAWT(); + try { + // ???AWT + /* + * Container parent = getParent(); if (parent != null) { return + * parent.getInputContext(); } + */ + return null; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the input method request handler which supports requests from input + * methods for this component, or null for default. + * + * @return the input method request handler which supports requests from + * input methods for this component, or null for default. + */ + public InputMethodRequests getInputMethodRequests() { + return null; + } + + /** + * Gets the locale of this Component. + * + * @return the locale of this Component. + */ + public Locale getLocale() { + toolkit.lockAWT(); + try { + // ???AWT + /* + * if (locale == null) { if (parent == null) { if (this instanceof + * Window) { return Locale.getDefault(); } // awt.150=no parent + * throw new + * IllegalComponentStateException(Messages.getString("awt.150")); + * //$NON-NLS-1$ } return getParent().getLocale(); } + */ + return locale; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the location of this component in the form of a point specifying the + * component's top-left corner in the screen's coordinate space. + * + * @return the Point giving the component's location in the screen's + * coordinate space. + * @throws IllegalComponentStateException + * if the component is not shown on the screen. + */ + public Point getLocationOnScreen() throws IllegalComponentStateException { + toolkit.lockAWT(); + try { + Point p = new Point(); + if (isShowing()) { + // ???AWT + /* + * Component comp; for (comp = this; comp != null && !(comp + * instanceof Window); comp = comp .getParent()) { + * p.translate(comp.getX(), comp.getY()); } if (comp instanceof + * Window) { p.translate(comp.getX(), comp.getY()); } + */ + return p; + } + // awt.151=component must be showing on the screen to determine its + // location + throw new IllegalComponentStateException(Messages.getString("awt.151")); //$NON-NLS-1$ + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the peer. This method should not be called directly by user + * applications. + * + * @return the ComponentPeer. + * @deprecated Replaced by isDisplayable(). + */ + @Deprecated + public ComponentPeer getPeer() { + toolkit.lockAWT(); + try { + if (behaviour.isDisplayable()) { + return peer; + } + return null; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets an array of the property change listeners registered to this + * Component. + * + * @return an array of the PropertyChangeListeners registered to this + * Component. + */ + public PropertyChangeListener[] getPropertyChangeListeners() { + return getPropertyChangeSupport().getPropertyChangeListeners(); + } + + /** + * Gets an array of PropertyChangeListener objects registered to this + * Component for the specified property. + * + * @param propertyName + * the property name. + * @return an array of PropertyChangeListener objects registered to this + * Component for the specified property. + */ + public PropertyChangeListener[] getPropertyChangeListeners(String propertyName) { + return getPropertyChangeSupport().getPropertyChangeListeners(propertyName); + } + + /** + * Gets the width of the Component. + * + * @return the width of the Component. + */ + public int getWidth() { + toolkit.lockAWT(); + try { + return w; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the x coordinate of the component's top-left corner. + * + * @return the x coordinate of the component's top-left corner. + */ + public int getX() { + toolkit.lockAWT(); + try { + return x; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the y coordinate of the component's top-left corner. + * + * @return the y coordinate of the component's top-left corner. + */ + public int getY() { + toolkit.lockAWT(); + try { + return y; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Got the focus. + * + * @param evt + * the Event. + * @param what + * the Object. + * @return true, if successful. + * @deprecated Replaced by processFocusEvent(FocusEvent) method. + */ + @Deprecated + public boolean gotFocus(Event evt, Object what) { + // to be overridden: do nothing, + // just return false to propagate event up to the parent container + return false; + } + + /** + * Handles event. + * + * @param evt + * the Event. + * @return true, if successful. + * @deprecated Replaced by processEvent(AWTEvent) method. + */ + @Deprecated + public boolean handleEvent(Event evt) { + switch (evt.id) { + case Event.ACTION_EVENT: + return action(evt, evt.arg); + case Event.GOT_FOCUS: + return gotFocus(evt, null); + case Event.LOST_FOCUS: + return lostFocus(evt, null); + case Event.MOUSE_DOWN: + return mouseDown(evt, evt.x, evt.y); + case Event.MOUSE_DRAG: + return mouseDrag(evt, evt.x, evt.y); + case Event.MOUSE_ENTER: + return mouseEnter(evt, evt.x, evt.y); + case Event.MOUSE_EXIT: + return mouseExit(evt, evt.x, evt.y); + case Event.MOUSE_MOVE: + return mouseMove(evt, evt.x, evt.y); + case Event.MOUSE_UP: + return mouseUp(evt, evt.x, evt.y); + case Event.KEY_ACTION: + case Event.KEY_PRESS: + return keyDown(evt, evt.key); + case Event.KEY_ACTION_RELEASE: + case Event.KEY_RELEASE: + return keyUp(evt, evt.key); + } + return false;// event not handled + } + + /** + * Checks whether the Component is the focus owner or not. + * + * @return true, if the Component is the focus owner, false otherwise. + */ + public boolean hasFocus() { + toolkit.lockAWT(); + try { + // ???AWT: return isFocusOwner(); + return false; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Hides the Component. + * + * @deprecated Replaced by setVisible(boolean) method. + */ + @Deprecated + public void hide() { + toolkit.lockAWT(); + try { + if (!visible) { + return; + } + prepare4HierarchyChange(); + visible = false; + moveFocusOnHide(); + behaviour.setVisible(false); + postEvent(new ComponentEvent(this, ComponentEvent.COMPONENT_HIDDEN)); + // ???AWT: finishHierarchyChange(this, parent, 0); + notifyInputMethod(null); + // ???AWT: invalidateRealParent(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Checks whether or not the point with the specified coordinates belongs to + * the Commponent. + * + * @param x + * the x coordinate of the Point. + * @param y + * the y coordinate of the Point. + * @return true, if the point with the specified coordinates belongs to the + * Commponent, false otherwise. + * @deprecated Replaced by contains(int, int) method. + */ + @Deprecated + public boolean inside(int x, int y) { + toolkit.lockAWT(); + try { + return x >= 0 && x < getWidth() && y >= 0 && y < getHeight(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Invalidates the component, this component and all parents above it are + * marked as needing to be laid out. + */ + public void invalidate() { + toolkit.lockAWT(); + try { + valid = false; + resetDefaultSize(); + // ???AWT: invalidateRealParent(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Checks whether or not the background color is set to this Component. + * + * @return true, if the background color is set to this Component, false + * otherwise. + */ + public boolean isBackgroundSet() { + toolkit.lockAWT(); + try { + return backColor != null; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Checks whether or not a cursor is set for the Component. + * + * @return true, if a cursor is set for the Component, false otherwise. + */ + public boolean isCursorSet() { + toolkit.lockAWT(); + try { + return cursor != null; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Checks whether or not this Component is displayable. + * + * @return true, if this Component is displayable, false otherwise. + */ + public boolean isDisplayable() { + toolkit.lockAWT(); + try { + return behaviour.isDisplayable(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Checks whether or not this component is painted to an buffer which is + * copied to the screen later. + * + * @return true, if this component is painted to an buffer which is copied + * to the screen later, false otherwise. + */ + public boolean isDoubleBuffered() { + toolkit.lockAWT(); + try { + // false by default + return false; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Checks whether or not this Component is enabled. + * + * @return true, if this Component is enabled, false otherwise. + */ + public boolean isEnabled() { + toolkit.lockAWT(); + try { + return enabled; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * "Recursive" isEnabled(). + * + * @return true if not only component itself is enabled but its heavyweight + * parent is also "indirectly" enabled. + */ + boolean isIndirectlyEnabled() { + Component comp = this; + while (comp != null) { + if (!comp.isLightweight() && !comp.isEnabled()) { + return false; + } + // ???AWT: comp = comp.getRealParent(); + } + return true; + } + + /** + * Checks if the component is key enabled. + * + * @return true, if the component is enabled and indirectly enabled. + */ + boolean isKeyEnabled() { + if (!isEnabled()) { + return false; + } + return isIndirectlyEnabled(); + } + + /** + * Gets only parent of a child component, but not owner of a window. + * + * @return parent of child component, null if component is a top-level + * (Window instance). + */ + // ???AWT + /* + * Container getRealParent() { return (!(this instanceof Window) ? + * getParent() : null); } public boolean isFocusCycleRoot(Container + * container) { toolkit.lockAWT(); try { return getFocusCycleRootAncestor() + * == container; } finally { toolkit.unlockAWT(); } } public boolean + * isFocusOwner() { toolkit.lockAWT(); try { return + * KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() == + * this; } finally { toolkit.unlockAWT(); } } + */ + + /** + * Checks whether or not this Component can be focusable. + * + * @return true, if this Component can be focusable, false otherwise. + * @deprecated Replaced by isFocusable(). + */ + @Deprecated + public boolean isFocusTraversable() { + toolkit.lockAWT(); + try { + overridenIsFocusable = false; + return focusable; // a Component must either be both focusable and + // focus traversable, or neither + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Checks if this Component can be focusable or not. + * + * @return true, if this Component can be focusable, false otherwise. + */ + public boolean isFocusable() { + toolkit.lockAWT(); + try { + return isFocusTraversable(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Checks if the Font is set for this Component or not. + * + * @return true, if the Font is set, false otherwise. + */ + public boolean isFontSet() { + toolkit.lockAWT(); + try { + return font != null; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Checks if foreground color is set for the Component or not. + * + * @return true, if is foreground color is set for the Component, false + * otherwise. + */ + public boolean isForegroundSet() { + toolkit.lockAWT(); + try { + return foreColor != null; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Returns true if this component has a lightweight peer. + * + * @return true, if this component has a lightweight peer, false if it has a + * native peer or no peer. + */ + public boolean isLightweight() { + toolkit.lockAWT(); + try { + return behaviour.isLightweight(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Checks whether or not this Component is shown. + * + * @return true, if this Component is shown, false otherwise. + */ + public boolean isShowing() { + // ???AWT + /* + * toolkit.lockAWT(); try { return (isVisible() && isDisplayable() && + * (parent != null) && parent.isShowing()); } finally { + * toolkit.unlockAWT(); } + */ + return false; + } + + /** + * Checks whether or not this Component is visible. + * + * @return true, if the Component is visible, false otherwise. + */ + public boolean isVisible() { + toolkit.lockAWT(); + try { + return visible; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Deprecated: replaced by processKeyEvent(KeyEvent) method. + * + * @param evt + * the Event. + * @param key + * the key code. + * @return true, if successful. + * @deprecated Replaced by replaced by processKeyEvent(KeyEvent) method. + */ + @Deprecated + public boolean keyDown(Event evt, int key) { + // to be overridden: do nothing, + // just return false to propagate event up to the parent container + return false; + } + + /** + * Deprecated: replaced by processKeyEvent(KeyEvent) method. + * + * @param evt + * the Event. + * @param key + * the key code. + * @return true, if successful. + * @deprecated Replaced by processKeyEvent(KeyEvent) method. + */ + @Deprecated + public boolean keyUp(Event evt, int key) { + // to be overridden: do nothing, + // just return false to propagate event up to the parent container + return false; + } + + /** + * Deprecated: Replaced by doLayout() method. + * + * @deprecated Replaced by doLayout() method. + */ + @Deprecated + public void layout() { + toolkit.lockAWT(); + try { + // Implemented in Container + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Deprecated: replaced by getComponentAt(int, int) method. + * + * @param x + * the x coordinate. + * @param y + * the y coordinate. + * @return The component. + * @deprecated Replaced by getComponentAt(int, int) method. + */ + @Deprecated + public Component locate(int x, int y) { + toolkit.lockAWT(); + try { + if (contains(x, y)) { + return this; + } + return null; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Deprecated: replaced by processFocusEvent(FocusEvent). + * + * @param evt + * the Event. + * @param what + * the Object. + * @return true, if successful. + * @deprecated Replaced by processFocusEvent(FocusEvent). + */ + @Deprecated + public boolean lostFocus(Event evt, Object what) { + // to be overridden: do nothing, + // just return false to propagate event up to the parent container + return false; + } + + /** + * Deprecated: replaced by processMouseEvent(MouseEvent) method. + * + * @param evt + * the MouseEvent. + * @param x + * the x coordinate. + * @param y + * the y coordinate. + * @return true, if successful. + * @deprecated Replaced by processMouseEvent(MouseEvent) method. + */ + @Deprecated + public boolean mouseDown(Event evt, int x, int y) { + // to be overridden: do nothing, + // just return false to propagate event up to the parent container + return false; + } + + /** + * Deprecated: replaced by getMinimumSize() method. + * + * @param evt + * the Event. + * @param x + * the x coordinate. + * @param y + * the y coordinate. + * @return true, if successful. + * @deprecated Replaced by getMinimumSize() method. + */ + @Deprecated + public boolean mouseDrag(Event evt, int x, int y) { + // to be overridden: do nothing, + // just return false to propagate event up to the parent container + return false; + } + + /** + * Replaced by processMouseEvent(MouseEvent) method. + * + * @param evt + * the Event. + * @param x + * the x coordinate. + * @param y + * the y coordinate. + * @return true, if successful. + * @deprecated replaced by processMouseEvent(MouseEvent) method. + */ + @Deprecated + public boolean mouseEnter(Event evt, int x, int y) { + // to be overridden: do nothing, + // just return false to propagate event up to the parent container + return false; + } + + /** + * Replaced by processMouseEvent(MouseEvent) method. + * + * @param evt + * the Event. + * @param x + * the x coordinate. + * @param y + * the y coordinate. + * @return true, if successful. + * @deprecated Replaced by processMouseEvent(MouseEvent) method. + */ + @Deprecated + public boolean mouseExit(Event evt, int x, int y) { + // to be overridden: do nothing, + // just return false to propagate event up to the parent container + return false; + } + + /** + * Replaced by processMouseEvent(MouseEvent) method. + * + * @param evt + * the Event. + * @param x + * the x coordinate. + * @param y + * the y coordinate. + * @deprecated Replaced by processMouseEvent(MouseEvent) method. + * @return true, if successful. + */ + @Deprecated + public boolean mouseMove(Event evt, int x, int y) { + // to be overridden: do nothing, + // just return false to propagate event up to the parent container + return false; + } + + /** + * Replaced by processMouseEvent(MouseEvent) method. + * + * @param evt + * the Event. + * @param x + * the x coordinate. + * @param y + * the y coordinate. + * @return true, if successful. + * @deprecated Replaced by processMouseEvent(MouseEvent) method. + */ + @Deprecated + public boolean mouseUp(Event evt, int x, int y) { + // to be overridden: do nothing, + // just return false to propagate event up to the parent container + return false; + } + + /** + * Deprecated: replaced by setLocation(int, int) method. + * + * @param x + * the x coordinates. + * @param y + * the y coordinates. + * @deprecated Replaced by setLocation(int, int) method. + */ + @Deprecated + public void move(int x, int y) { + toolkit.lockAWT(); + try { + boundsMaskParam = NativeWindow.BOUNDS_NOSIZE; + setBounds(x, y, w, h); + } finally { + toolkit.unlockAWT(); + } + } + + // ???AWT + /* + * @Deprecated public void nextFocus() { toolkit.lockAWT(); try { + * transferFocus(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); } finally { + * toolkit.unlockAWT(); } } + */ + + /** + * Returns a string representation of the component's state. + * + * @return the string representation of the component's state. + */ + protected String paramString() { + /* + * The format is based on 1.5 release behavior which can be revealed by + * the following code: Component c = new Component(){}; + * c.setVisible(false); System.out.println(c); + */ + toolkit.lockAWT(); + try { + return getName() + "," + getX() + "," + getY() + "," + getWidth() + "x" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + + getHeight() + (!isVisible() ? ",hidden" : ""); //$NON-NLS-1$ //$NON-NLS-2$ + } finally { + toolkit.unlockAWT(); + } + } + + @Deprecated + @SuppressWarnings("deprecation") + public boolean postEvent(Event evt) { + boolean handled = handleEvent(evt); + if (handled) { + return true; + } + // ???AWT + /* + * // propagate non-handled events up to parent Component par = parent; + * // try to call postEvent only on components which // override any of + * deprecated method handlers // while (par != null && + * !par.deprecatedEventHandler) { // par = par.parent; // } // translate + * event coordinates before posting it to parent if (par != null) { + * evt.translate(x, y); par.postEvent(evt); } + */ + return false; + } + + /** + * Prepares an image for rendering on the Component. + * + * @param image + * the Image to be prepared. + * @param observer + * the ImageObserver object to be notified as soon as the image + * is prepared. + * @return true if the image has been fully prepared, false otherwise. + */ + public boolean prepareImage(Image image, ImageObserver observer) { + toolkit.lockAWT(); + try { + return toolkit.prepareImage(image, -1, -1, observer); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Prepares an image for rendering on the Component with the specified + * width, height, and ImageObserver. + * + * @param image + * the Image to be prepared. + * @param width + * the width of scaled image. + * @param height + * the height of scaled height. + * @param observer + * the ImageObserver object to be notified as soon as the image + * is prepared. + * @return true if the image is been fully prepared, false otherwise. + */ + public boolean prepareImage(Image image, int width, int height, ImageObserver observer) { + toolkit.lockAWT(); + try { + return toolkit.prepareImage(image, width, height, observer); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Makes this Component undisplayable. + */ + public void removeNotify() { + toolkit.lockAWT(); + try { + // ???AWT + /* + * if (dropTarget != null) { dropTarget.removeNotify(peer); } + */ + prepare4HierarchyChange(); + // /???AWT: moveFocus(); + behaviour.removeNotify(); + // ???AWT: finishHierarchyChange(this, parent, 0); + removeNotifyInputContext(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Calls InputContext.removeNotify. + */ + private void removeNotifyInputContext() { + if (!inputMethodsEnabled) { + return; + } + InputContext ic = getInputContext(); + if (ic != null) { + // ???AWT: ic.removeNotify(this); + } + } + + /** + * This method is called when some property of a component changes, making + * it unfocusable, e. g. hide(), removeNotify(), setEnabled(false), + * setFocusable(false) is called, and therefore automatic forward focus + * traversal is necessary + */ + // ???AWT + /* + * void moveFocus() { // don't use transferFocus(), but query focus + * traversal policy directly // and if it returns null, transfer focus up + * cycle // and find next focusable component there KeyboardFocusManager kfm + * = KeyboardFocusManager.getCurrentKeyboardFocusManager(); Container root = + * kfm.getCurrentFocusCycleRoot(); Component nextComp = this; boolean + * success = !isFocusOwner(); while (!success) { if (root != + * nextComp.getFocusCycleRootAncestor()) { // component was probably removed + * from container // so focus will be lost in some time return; } nextComp = + * root.getFocusTraversalPolicy().getComponentAfter(root, nextComp); if + * (nextComp == this) { nextComp = null; // avoid looping } if (nextComp != + * null) { success = nextComp.requestFocusInWindow(); } else { nextComp = + * root; root = root.getFocusCycleRootAncestor(); // if no acceptable + * component is found at all - clear global // focus owner if (root == null) + * { if (nextComp instanceof Window) { Window wnd = (Window) nextComp; + * wnd.setFocusOwner(null); wnd.setRequestedFocus(null); } + * kfm.clearGlobalFocusOwner(); return; } } } } + */ + + /** + * For Container there's a difference between moving focus when being made + * invisible or made unfocusable in some other way, because when container + * is made invisible, component still remains visible, i. e. its hide() or + * setVisible() is not called. + */ + void moveFocusOnHide() { + // ???AWT: moveFocus(); + } + + /** + * Removes the property change listener registered for this component. + * + * @param listener + * the PropertyChangeListener. + */ + public void removePropertyChangeListener(PropertyChangeListener listener) { + getPropertyChangeSupport().removePropertyChangeListener(listener); + } + + /** + * Removes the property change listener registered fot this component for + * the specified propertyy. + * + * @param propertyName + * the property name. + * @param listener + * the PropertyChangeListener. + */ + public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + getPropertyChangeSupport().removePropertyChangeListener(propertyName, listener); + } + + /** + * Repaints the specified rectangle of this component within tm + * milliseconds. + * + * @param tm + * the time in milliseconds before updating. + * @param x + * the x coordinate of Rectangle. + * @param y + * the y coordinate of Rectangle. + * @param width + * the width of Rectangle. + * @param height + * the height of Rectangle. + */ + public void repaint(long tm, int x, int y, int width, int height) { + // ???AWT + /* + * toolkit.lockAWT(); try { if (width <= 0 || height <= 0 || + * (redrawManager == null) || !isShowing()) { return; } if (behaviour + * instanceof LWBehavior) { if (parent == null || !parent.visible || + * !parent.behaviour.isDisplayable()) { return; } if (repaintRegion == + * null) { repaintRegion = new MultiRectArea(new Rectangle(x, y, width, + * height)); } repaintRegion.intersect(new Rectangle(0, 0, this.w, + * this.h)); repaintRegion.translate(this.x, this.y); + * parent.repaintRegion = repaintRegion; repaintRegion = null; + * parent.repaint(tm, x + this.x, y + this.y, width, height); } else { + * if (repaintRegion != null) { redrawManager.addUpdateRegion(this, + * repaintRegion); repaintRegion = null; } else { + * redrawManager.addUpdateRegion(this, new Rectangle(x, y, width, + * height)); } + * toolkit.getSystemEventQueueCore().notifyEventMonitor(toolkit); } } + * finally { toolkit.unlockAWT(); } + */ + } + + /** + * Post event. + * + * @param e + * the e. + */ + void postEvent(AWTEvent e) { + getToolkit().getSystemEventQueueImpl().postEvent(e); + } + + /** + * Repaints the specified Rectangle of this Component. + * + * @param x + * the x coordinate of Rectangle. + * @param y + * the y coordinate of Rectangle. + * @param width + * the width of Rectangle. + * @param height + * the height of Rectangle. + */ + public void repaint(int x, int y, int width, int height) { + toolkit.lockAWT(); + try { + repaint(0, x, y, width, height); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Repaints this component. + */ + public void repaint() { + toolkit.lockAWT(); + try { + if (w > 0 && h > 0) { + repaint(0, 0, 0, w, h); + } + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Repaints the component within tm milliseconds. + * + * @param tm + * the time in milliseconds before updating. + */ + public void repaint(long tm) { + toolkit.lockAWT(); + try { + repaint(tm, 0, 0, w, h); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Requests that this Component get the input focus temporarily. This + * component must be displayable, visible, and focusable. + * + * @param temporary + * this parameter is true if the focus change is temporary, when + * the window loses the focus. + * @return true if the focus change request is succeeded, false otherwise. + */ + protected boolean requestFocus(boolean temporary) { + toolkit.lockAWT(); + try { + // ???AWT: return requestFocusImpl(temporary, true, false); + } finally { + toolkit.unlockAWT(); + } + // ???AWT + return false; + } + + /** + * Requests that this Component get the input focus. This component must be + * displayable, visible, and focusable. + */ + public void requestFocus() { + toolkit.lockAWT(); + try { + requestFocus(false); + } finally { + toolkit.unlockAWT(); + } + } + + // ???AWT + /* + * protected boolean requestFocusInWindow(boolean temporary) { + * toolkit.lockAWT(); try { Window wnd = getWindowAncestor(); if ((wnd == + * null) || !wnd.isFocused()) { return false; } return + * requestFocusImpl(temporary, false, false); } finally { + * toolkit.unlockAWT(); } } boolean requestFocusImpl(boolean temporary, + * boolean crossWindow, boolean rejectionRecovery) { if (!rejectionRecovery + * && isFocusOwner()) { return true; } Window wnd = getWindowAncestor(); + * Container par = getRealParent(); if ((par != null) && par.isRemoved) { + * return false; } if (!isShowing() || !isFocusable() || + * !wnd.isFocusableWindow()) { return false; } return + * KeyboardFocusManager.getCurrentKeyboardFocusManager().requestFocus(this, + * temporary, crossWindow, true); } public boolean requestFocusInWindow() { + * toolkit.lockAWT(); try { return requestFocusInWindow(false); } finally { + * toolkit.unlockAWT(); } } + */ + + /** + * Deprecated: replaced by setBounds(int, int, int, int) method. + * + * @param x + * the x coordinate. + * @param y + * the y coordinate. + * @param w + * the width. + * @param h + * the height. + * @deprecated Replaced by setBounds(int, int, int, int) method. + */ + @Deprecated + public void reshape(int x, int y, int w, int h) { + toolkit.lockAWT(); + try { + setBounds(x, y, w, h, boundsMaskParam, true); + boundsMaskParam = 0; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Sets rectangle for this Component to be the rectangle with the specified + * x,y coordinates of the top-left corner and the width and height. + * + * @param x + * the x coordinate of the rectangle's top-left corner. + * @param y + * the y coordinate of the rectangle's top-left corner. + * @param w + * the width of rectangle. + * @param h + * the height of rectangle. + */ + public void setBounds(int x, int y, int w, int h) { + toolkit.lockAWT(); + try { + reshape(x, y, w, h); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Sets rectangle for this Component to be the rectangle with the specified + * x,y coordinates of the top-left corner and the width and height and posts + * the appropriate events. + * + * @param x + * the x coordinate of the rectangle's top-left corner. + * @param y + * the y coordinate of the rectangle's top-left corner. + * @param w + * the width of rectangle. + * @param h + * the height of rectangle. + * @param bMask + * the bitmask of bounds options. + * @param updateBehavior + * the whether to update the behavoir's bounds as well. + */ + void setBounds(int x, int y, int w, int h, int bMask, boolean updateBehavior) { + int oldX = this.x; + int oldY = this.y; + int oldW = this.w; + int oldH = this.h; + setBoundsFields(x, y, w, h, bMask); + // Moved + if ((oldX != this.x) || (oldY != this.y)) { + // ???AWT: invalidateRealParent(); + postEvent(new ComponentEvent(this, ComponentEvent.COMPONENT_MOVED)); + spreadHierarchyBoundsEvents(this, HierarchyEvent.ANCESTOR_MOVED); + } + // Resized + if ((oldW != this.w) || (oldH != this.h)) { + invalidate(); + postEvent(new ComponentEvent(this, ComponentEvent.COMPONENT_RESIZED)); + spreadHierarchyBoundsEvents(this, HierarchyEvent.ANCESTOR_RESIZED); + } + if (updateBehavior) { + behaviour.setBounds(this.x, this.y, this.w, this.h, bMask); + } + notifyInputMethod(new Rectangle(x, y, w, h)); + } + + /** + * Calls InputContextImpl.notifyClientWindowChanged. + * + * @param bounds + * the bounds. + */ + void notifyInputMethod(Rectangle bounds) { + // only Window actually notifies IM of bounds change + } + + /** + * Sets the bounds fields. + * + * @param x + * the x. + * @param y + * the y. + * @param w + * the w. + * @param h + * the h. + * @param bMask + * the b mask. + */ + private void setBoundsFields(int x, int y, int w, int h, int bMask) { + if ((bMask & NativeWindow.BOUNDS_NOSIZE) == 0) { + this.w = w; + this.h = h; + } + if ((bMask & NativeWindow.BOUNDS_NOMOVE) == 0) { + this.x = x; + this.y = y; + } + } + + /** + * Gets the native insets. + * + * @return the native insets. + */ + Insets getNativeInsets() { + return new Insets(0, 0, 0, 0); + } + + /** + * Gets the insets. + * + * @return the insets. + */ + Insets getInsets() { + return new Insets(0, 0, 0, 0); + } + + /** + * Checks if is mouse exited expected. + * + * @return true, if is mouse exited expected. + */ + boolean isMouseExitedExpected() { + return mouseExitedExpected; + } + + /** + * Sets the mouse exited expected. + * + * @param expected + * the new mouse exited expected. + */ + void setMouseExitedExpected(boolean expected) { + mouseExitedExpected = expected; + } + + /** + * Sets the new bounding rectangle for this Component. + * + * @param r + * the new bounding rectangle. + */ + public void setBounds(Rectangle r) { + toolkit.lockAWT(); + try { + setBounds(r.x, r.y, r.width, r.height); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Sets the component orientation which affects the component's elements and + * text within this component. + * + * @param o + * the ComponentOrientation object. + */ + public void setComponentOrientation(ComponentOrientation o) { + ComponentOrientation oldOrientation; + toolkit.lockAWT(); + try { + oldOrientation = orientation; + orientation = o; + } finally { + toolkit.unlockAWT(); + } + firePropertyChange("componentOrientation", oldOrientation, orientation); //$NON-NLS-1$ + invalidate(); + } + + /** + * Sets the specified cursor for this Component. + * + * @param cursor + * the new Cursor. + */ + public void setCursor(Cursor cursor) { + toolkit.lockAWT(); + try { + this.cursor = cursor; + setCursor(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Set current cursor shape to Component's Cursor. + */ void setCursor() { - if (isDisplayable()) { // && isShowing()) { - // Rectangle absRect = new Rectangle(getLocationOnScreen(), getSize()); - //Point absPointerPos = toolkit.dispatcher.mouseDispatcher.getPointerPos(); + if (isDisplayable() && isShowing()) { + Rectangle absRect = new Rectangle(getLocationOnScreen(), getSize()); + Point absPointerPos = toolkit.dispatcher.mouseDispatcher.getPointerPos(); // ???AWT /* * if (absRect.contains(absPointerPos)) { // set Cursor only on @@ -70,280 +3969,318 @@ public class Component { */ } } - - public void setFocusable(boolean focusable) { boolean oldFocusable; - calledSetFocusable = true; - oldFocusable = this.focusable; - this.focusable = focusable; - if (!focusable) { - moveFocus(); + + /** + * Gets the ancestor Cursor if Component is disabled (directly or via an + * ancestor) even if Cursor is explicitly set. + * + * @param value + * the value. + * @return the actual Cursor to be displayed. + */ + // ???AWT + /* + * Cursor getRealCursor() { Component cursorAncestor = getCursorAncestor(); + * return cursorAncestor != null ? cursorAncestor.getCursor() : + * Cursor.getDefaultCursor(); } + */ + + /** + * Gets the ancestor(or component itself) whose cursor is set when pointer + * is inside component + * + * @return the actual Cursor to be displayed. + */ + // ???AWT + /* + * Component getCursorAncestor() { Component comp; for (comp = this; comp != + * null; comp = comp.getParent()) { if (comp instanceof Window || + * comp.isCursorSet() && comp.isKeyEnabled()) { return comp; } } return + * null; } public void setDropTarget(DropTarget dt) { toolkit.lockAWT(); try + * { if (dropTarget == dt) { return; } DropTarget oldDropTarget = + * dropTarget; dropTarget = dt; if (oldDropTarget != null) { if + * (behaviour.isDisplayable()) { oldDropTarget.removeNotify(peer); } + * oldDropTarget.setComponent(null); } if (dt != null) { + * dt.setComponent(this); if (behaviour.isDisplayable()) { + * dt.addNotify(peer); } } } finally { toolkit.unlockAWT(); } } + */ + + /** + * Sets this component to the "enabled" or "disabled" state depending on the + * specified boolean parameter. + * + * @param value + * true if this component should be enabled; false if this + * component should be disabled. + */ + public void setEnabled(boolean value) { + toolkit.lockAWT(); + try { + enable(value); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Sets the enabled impl. + * + * @param value + * the new enabled impl. + */ + void setEnabledImpl(boolean value) { + if (enabled != value) { + enabled = value; + setCursor(); + if (!enabled) { + moveFocusOnHide(); + } + behaviour.setEnabled(value); + } + } + + // ???AWT + /* + * private void fireAccessibleStateChange(AccessibleState state, boolean + * value) { if (behaviour.isLightweight()) { return; } AccessibleContext ac + * = getAccessibleContext(); if (ac != null) { AccessibleState oldValue = + * null; AccessibleState newValue = null; if (value) { newValue = state; } + * else { oldValue = state; } + * ac.firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY, + * oldValue, newValue); } } + */ + + // ???AWT + /* + * public void setFocusTraversalKeys(int id, Set + * keystrokes) { Set oldTraversalKeys; String + * propName = "FocusTraversalKeys"; //$NON-NLS-1$ toolkit.lockAWT(); try { + * Integer kId = new Integer(id); + * KeyboardFocusManager.checkTraversalKeysID(traversalKeys, kId); + * Map> keys = new HashMap>(); for (int kid : traversalIDs) { Integer + * key = new Integer(kid); keys.put(key, getFocusTraversalKeys(kid)); } + * KeyboardFocusManager.checkKeyStrokes(traversalIDs, keys, kId, + * keystrokes); oldTraversalKeys = traversalKeys.get(new Integer(id)); // + * put a copy of keystrokes object into map: Set + * newKeys = keystrokes; if (keystrokes != null) { newKeys = new + * HashSet(keystrokes); } traversalKeys.put(kId, newKeys); + * String direction = ""; //$NON-NLS-1$ switch (id) { case + * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS: direction = "forward"; + * //$NON-NLS-1$ break; case KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS: + * direction = "backward"; //$NON-NLS-1$ break; case + * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS: direction = "upCycle"; + * //$NON-NLS-1$ break; case KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS: + * direction = "downCycle"; //$NON-NLS-1$ break; } propName = direction + + * propName; } finally { toolkit.unlockAWT(); } firePropertyChange(propName, + * oldTraversalKeys, keystrokes); } + */ + + /** + * Sets the focus traversal keys state for this component. + * + * @param value + * true if the focus traversal keys state is enabled, false if + * the focus traversal keys state is disabled. + */ + public void setFocusTraversalKeysEnabled(boolean value) { + boolean oldFocusTraversalKeysEnabled; + toolkit.lockAWT(); + try { + oldFocusTraversalKeysEnabled = focusTraversalKeysEnabled; + focusTraversalKeysEnabled = value; + } finally { + toolkit.unlockAWT(); + } + firePropertyChange("focusTraversalKeysEnabled", oldFocusTraversalKeysEnabled, //$NON-NLS-1$ + focusTraversalKeysEnabled); + } + + // ???AWT + public void setFocusable(boolean focusable) { + boolean oldFocusable; + toolkit.lockAWT(); + try { + calledSetFocusable = true; + oldFocusable = this.focusable; + this.focusable = focusable; + if (!focusable) { + // moveFocus(); + } + } finally { + toolkit.unlockAWT(); } firePropertyChange("focusable", oldFocusable, focusable); //$NON-NLS-1$ } - void moveFocus() { - // Fake method + public Font getFont() { + toolkit.lockAWT(); + try { + return (font == null) && (parent != null) ? parent.getFont() : font; + } finally { + toolkit.unlockAWT(); + } } - - - public void setFont(Font f) { + + /** + * Sets the font for this Component. + * + * @param f + * the new font of the Component. + */ + public void setFont(Font f) { Font oldFont; - oldFont = font; - setFontImpl(f); - firePropertyChange("font", oldFont, font); //$NON-NLS-1$ - } - - void setFontImpl(Font f) { - font = f; - invalidate(); - /* - if (isShowing()) { - repaint(); - } - */ - } - - public int getBaseline(int width, int height) { - if (width < 0 || height < 0) { - throw new IllegalArgumentException( - "Width and height must be >= 0"); - } - return -1; - } - - public void setLocation(Point p) { - setLocation(p.x, p.y); - } - - public void setLocation(int x, int y) { - move(x, y); - } - - public void move(int x, int y) { - boundsMaskParam = NativeWindow.BOUNDS_NOSIZE; - setBounds(x, y, w, h); - } - - public void repaint() { - // Android implementation, don't need to paint. - } - - public void validate() { - validateImpl(); - } - - void validateImpl() { - valid = true; - } - - public void addNotify() { - /* toolkit.lockAWT(); try { - prepare4HierarchyChange(); - //behaviour.addNotify(); - // ???AWT - // finishHierarchyChange(this, parent, 0); - // if (dropTarget != null) { - // dropTarget.addNotify(peer); - // } + oldFont = font; + setFontImpl(f); } finally { toolkit.unlockAWT(); } - */ - } - - Insets getNativeInsets() { - return new Insets(0, 0, 0, 0); + firePropertyChange("font", oldFont, font); //$NON-NLS-1$ } - Insets getInsets() { - return new Insets(0, 0, 0, 0); - } - - Color getDefaultBackground() { - // ???AWT: return getWindowAncestor().getDefaultBackground(); - return getBackground(); + /** + * Sets the font impl. + * + * @param f + * the new font impl. + */ + void setFontImpl(Font f) { + font = f; + invalidate(); + if (isShowing()) { + repaint(); + } } - Color getDefaultForeground() { - // ???AWT return getWindowAncestor().getDefaultForeground(); - return getForeground(); + /** + * Invalidate the component if it inherits the font from the parent. This + * method is overridden in Container. + * + * @return true if the component was invalidated, false otherwise. + */ + boolean propagateFont() { + if (font == null) { + invalidate(); + return true; + } + return false; } - - public Color getBackground() { - if (backColor == null && parent != null) { - return parent.getBackground(); - } - - return backColor; - } - - public Color getForeground() { - if (foreColor == null && parent != null) { - return parent.getForeground(); - } - - return foreColor; - } - - public boolean isBackgroundSet() { - return backColor != null; - } - - public Color getTextColor() { - Color c = getForeground(); - return (c != null) ? c : getDefaultForeground(); - } + /** + * Sets the foreground color for this Component. + * + * @param c + * the new foreground color. + */ public void setForeground(Color c) { Color oldFgColor; - oldFgColor = foreColor; - foreColor = c; + toolkit.lockAWT(); + try { + oldFgColor = foreColor; + foreColor = c; + } finally { + toolkit.unlockAWT(); + } firePropertyChange("foreground", oldFgColor, foreColor); //$NON-NLS-1$ repaint(); } + /** + * Sets the background color for the Component. + * + * @param c + * the new background color for this component. + */ public void setBackground(Color c) { Color oldBkColor; - oldBkColor = backColor; - backColor = c; + toolkit.lockAWT(); + try { + oldBkColor = backColor; + backColor = c; + } finally { + toolkit.unlockAWT(); + } firePropertyChange("background", oldBkColor, backColor); //$NON-NLS-1$ repaint(); } - - public boolean isMaximumSizeSet() { - return maximumSize != null; + + /** + * Sets the flag for whether paint messages received from the operating + * system should be ignored or not. + * + * @param value + * true if paint messages received from the operating system + * should be ignored, false otherwise. + */ + public void setIgnoreRepaint(boolean value) { + toolkit.lockAWT(); + try { + ignoreRepaint = value; + } finally { + toolkit.unlockAWT(); + } } - public boolean isMinimumSizeSet() { - return minimumSize != null; + /** + * Sets the locale of the component. + * + * @param locale + * the new Locale. + */ + public void setLocale(Locale locale) { + Locale oldLocale; + toolkit.lockAWT(); + try { + oldLocale = this.locale; + this.locale = locale; + } finally { + toolkit.unlockAWT(); + } + firePropertyChange("locale", oldLocale, locale); //$NON-NLS-1$ } - public boolean isPreferredSizeSet() { - return preferredSize != null; + /** + * Sets the location of the Component to the specified point. + * + * @param p + * the new location of the Component. + */ + public void setLocation(Point p) { + toolkit.lockAWT(); + try { + setLocation(p.x, p.y); + } finally { + toolkit.unlockAWT(); + } } - public Dimension getMaximumSize() { - return isMaximumSizeSet() ? new Dimension(maximumSize) : new Dimension(Short.MAX_VALUE, Short.MAX_VALUE); + /** + * Sets the location of the Component to the specified x, y coordinates. + * + * @param x + * the x coordinate. + * @param y + * the y coordinate. + */ + public void setLocation(int x, int y) { + toolkit.lockAWT(); + try { + move(x, y); + } finally { + toolkit.unlockAWT(); + } } - public Dimension getMinimumSize() { - return minimumSize(); - } - - @Deprecated - public Dimension minimumSize() { - if (isMinimumSizeSet()) { - return (Dimension)minimumSize.clone(); - } - Dimension defSize = getDefaultMinimumSize(); - if (defSize != null) { - return (Dimension)defSize.clone(); - } - return isDisplayable() ? new Dimension(1, 1) : new Dimension(w, h); - } - - public Dimension getPreferredSize() { - return preferredSize(); - } - - @Deprecated - public Dimension preferredSize() { - if (isPreferredSizeSet()) { - return new Dimension(preferredSize); - } - Dimension defSize = getDefaultPreferredSize(); - if (defSize != null) { - return new Dimension(defSize); - } - return new Dimension(getMinimumSize()); - } - - public void setMaximumSize(Dimension maximumSize) { - Dimension oldMaximumSize; - oldMaximumSize = this.maximumSize; - if (oldMaximumSize != null) { - oldMaximumSize = oldMaximumSize.getSize(); - } - if (this.maximumSize == null) { - if (maximumSize != null) { - this.maximumSize = new Dimension(maximumSize); - } - } else { - if (maximumSize != null) { - this.maximumSize.setSize(maximumSize); - } else { - this.maximumSize = null; - } - } - firePropertyChange("maximumSize", oldMaximumSize, this.maximumSize); //$NON-NLS-1$ - } - - public void setMinimumSize(Dimension minimumSize) { - Dimension oldMinimumSize; - oldMinimumSize = this.minimumSize; - if (oldMinimumSize != null) { - oldMinimumSize = oldMinimumSize.getSize(); - } - if (this.minimumSize == null) { - if (minimumSize != null) { - this.minimumSize = new Dimension(minimumSize); - } - } else { - if (minimumSize != null) { - this.minimumSize.setSize(minimumSize); - } else { - this.minimumSize = null; - } - } - firePropertyChange("minimumSize", oldMinimumSize, this.minimumSize); //$NON-NLS-1$ - } - - public void setPreferredSize(Dimension preferredSize) { - Dimension oldPreferredSize; - oldPreferredSize = this.preferredSize; - if (oldPreferredSize != null) { - oldPreferredSize = oldPreferredSize.getSize(); - } - if (this.preferredSize == null) { - if (preferredSize != null) { - this.preferredSize = new Dimension(preferredSize); - } - } else { - if (preferredSize != null) { - this.preferredSize.setSize(preferredSize); - } else { - this.preferredSize = null; - } - } - firePropertyChange("preferredSize", oldPreferredSize, this.preferredSize); //$NON-NLS-1$ - } - - Dimension getDefaultMinimumSize() { - return null; - } - - Dimension getDefaultPreferredSize() { - return null; - } - - void resetDefaultSize() { - } - - public boolean isEnabled() { - return enabled; - } - - public boolean isVisible() { - return visible; - } - - public boolean isDisplayable() { - return isVisible(); //behaviour.isDisplayable(); - } - - public void setVisible(boolean b) { + /** + * Sets the visibility state of the component. + * + * @param b + * true if the component is visible, false if the component is + * not shown. + */ + public void setVisible(boolean b) { // show() & hide() are not deprecated for Window, // so have to call them from setVisible() show(b); @@ -356,42 +4293,32 @@ public class Component { */ @Deprecated public void show() { - if (visible) { - return; - } - /* - prepare4HierarchyChange(); - mapToDisplay(true); - validate(); - */ - visible = true; - /* - //behaviour.setVisible(true); - postEvent(new ComponentEvent(this, ComponentEvent.COMPONENT_SHOWN)); - // ???AWT: finishHierarchyChange(this, parent, 0); - notifyInputMethod(new Rectangle(x, y, w, h)); - // ???AWT: invalidateRealParent(); - */ + toolkit.lockAWT(); + try { + if (visible) { + return; + } + prepare4HierarchyChange(); + mapToDisplay(true); + validate(); + visible = true; + behaviour.setVisible(true); + postEvent(new ComponentEvent(this, ComponentEvent.COMPONENT_SHOWN)); + // ???AWT: finishHierarchyChange(this, parent, 0); + notifyInputMethod(new Rectangle(x, y, w, h)); + // ???AWT: invalidateRealParent(); + } finally { + toolkit.unlockAWT(); + } } - public void hide() { - if (!visible) { - return; - } - // prepare4HierarchyChange(); - visible = false; - - /* - moveFocusOnHide(); - //behaviour.setVisible(false); - postEvent(new ComponentEvent(this, ComponentEvent.COMPONENT_HIDDEN)); - // ???AWT: finishHierarchyChange(this, parent, 0); - notifyInputMethod(null); - // ???AWT: invalidateRealParent(); - */ - - } - + /** + * Deprecated: replaced by setVisible(boolean) method. + * + * @param b + * the visibility's state. + * @deprecated Replaced by setVisible(boolean) method. + */ @Deprecated public void show(boolean b) { if (b) { @@ -400,208 +4327,1851 @@ public class Component { hide(); } } - - public void applyComponentOrientation(ComponentOrientation orientation) { - if (orientation == null) { - throw new NullPointerException(); - } - setComponentOrientation(orientation); - } - - public ComponentOrientation getComponentOrientation() { - return orientation; - } - public void setComponentOrientation(ComponentOrientation o) { - ComponentOrientation oldOrientation; - oldOrientation = orientation; - orientation = o; - firePropertyChange("componentOrientation", oldOrientation, orientation); //$NON-NLS-1$ - invalidate(); - } -/* - final boolean canBeFocusOwner() { - // It is enabled, visible, focusable. - if (isEnabled() && isDisplayable() && isVisible() && isFocusable()) { - return true; - } - return false; - } -*/ - public boolean inside(int x, int y) { - return x >= 0 && x < getWidth() && y >= 0 && y < getHeight(); - } - + // ???AWT + /* + * void transferFocus(int dir) { Container root = null; if (this instanceof + * Container) { Container cont = (Container) this; if + * (cont.isFocusCycleRoot()) { root = cont.getFocusTraversalRoot(); } } if + * (root == null) { root = getFocusCycleRootAncestor(); } // transfer focus + * up cycle if root is unreachable Component comp = this; while ((root != + * null) && !(root.isFocusCycleRoot() && root.isShowing() && + * root.isEnabled() && root .isFocusable())) { comp = root; root = + * root.getFocusCycleRootAncestor(); } if (root == null) { return; } + * FocusTraversalPolicy policy = root.getFocusTraversalPolicy(); Component + * nextComp = null; switch (dir) { case + * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS: nextComp = + * policy.getComponentAfter(root, comp); break; case + * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS: nextComp = + * policy.getComponentBefore(root, comp); break; } if (nextComp != null) { + * nextComp.requestFocus(false); } } public void transferFocus() { + * toolkit.lockAWT(); try { nextFocus(); } finally { toolkit.unlockAWT(); } + * } public void transferFocusBackward() { toolkit.lockAWT(); try { + * transferFocus(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); } finally { + * toolkit.unlockAWT(); } } public void transferFocusUpCycle() { + * toolkit.lockAWT(); try { KeyboardFocusManager kfm = + * KeyboardFocusManager.getCurrentKeyboardFocusManager(); Container root = + * kfm.getCurrentFocusCycleRoot(); if(root == null) { return; } boolean + * success = false; Component nextComp = null; Container newRoot = root; do + * { nextComp = newRoot instanceof Window ? + * newRoot.getFocusTraversalPolicy() .getDefaultComponent(newRoot) : + * newRoot; newRoot = newRoot.getFocusCycleRootAncestor(); if (nextComp == + * null) { break; } success = nextComp.requestFocusInWindow(); if (newRoot + * == null) { break; } kfm.setGlobalCurrentFocusCycleRoot(newRoot); } while + * (!success); if (!success && root != newRoot) { + * kfm.setGlobalCurrentFocusCycleRoot(root); } } finally { + * toolkit.unlockAWT(); } } + */ - public boolean isValid() { - return valid; //&& behaviour.isDisplayable(); - } - - public void invalidate() { - valid = false; - resetDefaultSize(); - } - - void invalidateParent() { - if (parent != null) { - parent.invalidateIfValid(); - } - } - - final void invalidateIfValid() { - if (isValid()) { - invalidate(); - } - } - - public void addPropertyChangeListener(//String name, - PropertyChangeListener listener) { - if (listener == null) { - return; - } - if (propertyChangeSupport == null) { - propertyChangeSupport = new PropertyChangeSupport(this); - } - propertyChangeSupport.addPropertyChangeListener(listener); - } - - public void removePropertyChangeListener( - PropertyChangeListener listener) { - if (listener == null || propertyChangeSupport == null) { - return; - } - propertyChangeSupport.removePropertyChangeListener(listener); - } - - private void firePropertyChangeImpl(String propertyName, Object oldValue, Object newValue) { - PropertyChangeSupport pcs; - if (propertyChangeSupport == null) { - return; - } - pcs = propertyChangeSupport; - pcs.firePropertyChange(propertyName, oldValue, newValue); - } - - protected void firePropertyChange(String propertyName, int oldValue, int newValue) { - firePropertyChangeImpl(propertyName, new Integer(oldValue), new Integer(newValue)); - } - - protected void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) { - firePropertyChangeImpl(propertyName, Boolean.valueOf(oldValue), Boolean.valueOf(newValue)); - } - - protected void firePropertyChange(final String propertyName, final Object oldValue, - final Object newValue) { - firePropertyChangeImpl(propertyName, oldValue, newValue); - } - - public void firePropertyChange(String propertyName, byte oldValue, byte newValue) { - firePropertyChangeImpl(propertyName, new Byte(oldValue), new Byte(newValue)); - } - - public void firePropertyChange(String propertyName, char oldValue, char newValue) { - firePropertyChangeImpl(propertyName, new Character(oldValue), new Character(newValue)); - } - - public void firePropertyChange(String propertyName, short oldValue, short newValue) { - firePropertyChangeImpl(propertyName, new Short(oldValue), new Short(newValue)); - } - - public void firePropertyChange(String propertyName, long oldValue, long newValue) { - firePropertyChangeImpl(propertyName, new Long(oldValue), new Long(newValue)); - } - - public void firePropertyChange(String propertyName, float oldValue, float newValue) { - firePropertyChangeImpl(propertyName, new Float(oldValue), new Float(newValue)); - } - - public void firePropertyChange(String propertyName, double oldValue, double newValue) { - firePropertyChangeImpl(propertyName, new Double(oldValue), new Double(newValue)); - } - - public void setSize(int width, int height) { - // toolkit.lockAWT(); + /** + * Validates that this component has a valid layout. + */ + public void validate() { + toolkit.lockAWT(); try { - resize(width, height); + if (!behaviour.isDisplayable()) { + return; + } + validateImpl(); } finally { - // toolkit.unlockAWT(); + toolkit.unlockAWT(); } } /** - * Sets the size of the Component specified by Dimension object. - * - * @param d - * the new size of the Component. + * Validate impl. */ - public void setSize(Dimension d) { - resize(d); + void validateImpl() { + valid = true; } - public void resize(int width, int height) { - boundsMaskParam = NativeWindow.BOUNDS_NOMOVE; - setBounds(x, y, width, height); - - // MOD: impl - // graphics.resize(width, height); - } - - public void reshape(int x, int y, int w, int h) { - setBounds(x, y, w, h, boundsMaskParam, true); - boundsMaskParam = 0; - } - - public void setBounds(int x, int y, int w, int h) { - reshape(x, y, w, h); + /** + * Gets the native window. + * + * @return the native window. + */ + NativeWindow getNativeWindow() { + return behaviour.getNativeWindow(); } - void setBounds(int x, int y, int w, int h, int bMask, boolean updateBehavior) { - int oldX = this.x; - int oldY = this.y; - int oldW = this.w; - int oldH = this.h; - setBoundsFields(x, y, w, h, bMask); - // Moved - /* - if ((oldX != this.x) || (oldY != this.y)) { + /** + * Checks whether or not a maximum size is set for the Component. + * + * @return true, if the maximum size is set for the Component, false + * otherwise. + */ + public boolean isMaximumSizeSet() { + toolkit.lockAWT(); + try { + return maximumSize != null; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Checks whether or not the minimum size is set for the component. + * + * @return true, if the minimum size is set for the component, false + * otherwise. + */ + public boolean isMinimumSizeSet() { + toolkit.lockAWT(); + try { + return minimumSize != null; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Checks whether or not the preferred size is set for the Component. + * + * @return true, if the preferred size is set for the Component, false + * otherwise. + */ + public boolean isPreferredSizeSet() { + toolkit.lockAWT(); + try { + return preferredSize != null; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the maximum size of the Component. + * + * @return the maximum size of the Component. + */ + public Dimension getMaximumSize() { + toolkit.lockAWT(); + try { + return isMaximumSizeSet() ? new Dimension(maximumSize) : new Dimension(Short.MAX_VALUE, + Short.MAX_VALUE); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the minimum size of the Component. + * + * @return the minimum size of the Component. + */ + public Dimension getMinimumSize() { + toolkit.lockAWT(); + try { + return minimumSize(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Deprecated: replaced by getMinimumSize() method. + * + * @return the Dimension. + * @deprecated Replaced by getMinimumSize() method. + */ + @Deprecated + public Dimension minimumSize() { + toolkit.lockAWT(); + try { + if (isMinimumSizeSet()) { + return (Dimension)minimumSize.clone(); + } + Dimension defSize = getDefaultMinimumSize(); + if (defSize != null) { + return (Dimension)defSize.clone(); + } + return isDisplayable() ? new Dimension(1, 1) : new Dimension(w, h); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the preferred size of the Component. + * + * @return the preferred size of the Component. + */ + public Dimension getPreferredSize() { + toolkit.lockAWT(); + try { + return preferredSize(); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Deprecated: replaced by getPreferredSize() method. + * + * @return the Dimension. + * @deprecated Replaced by getPreferredSize() method. + */ + @Deprecated + public Dimension preferredSize() { + toolkit.lockAWT(); + try { + if (isPreferredSizeSet()) { + return new Dimension(preferredSize); + } + Dimension defSize = getDefaultPreferredSize(); + if (defSize != null) { + return new Dimension(defSize); + } + return new Dimension(getMinimumSize()); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Sets the maximum size of the Component. + * + * @param maximumSize + * the new maximum size of the Component. + */ + public void setMaximumSize(Dimension maximumSize) { + Dimension oldMaximumSize; + toolkit.lockAWT(); + try { + oldMaximumSize = this.maximumSize; + if (oldMaximumSize != null) { + oldMaximumSize = oldMaximumSize.getSize(); + } + if (this.maximumSize == null) { + if (maximumSize != null) { + this.maximumSize = new Dimension(maximumSize); + } + } else { + if (maximumSize != null) { + this.maximumSize.setSize(maximumSize); + } else { + this.maximumSize = null; + } + } + } finally { + toolkit.unlockAWT(); + } + firePropertyChange("maximumSize", oldMaximumSize, this.maximumSize); //$NON-NLS-1$ + toolkit.lockAWT(); + try { // ???AWT: invalidateRealParent(); - postEvent(new ComponentEvent(this, ComponentEvent.COMPONENT_MOVED)); - spreadHierarchyBoundsEvents(this, HierarchyEvent.ANCESTOR_MOVED); + } finally { + toolkit.unlockAWT(); } - // Resized - if ((oldW != this.w) || (oldH != this.h)) { - invalidate(); - postEvent(new ComponentEvent(this, ComponentEvent.COMPONENT_RESIZED)); - spreadHierarchyBoundsEvents(this, HierarchyEvent.ANCESTOR_RESIZED); - } - if (updateBehavior) { - //behaviour.setBounds(this.x, this.y, this.w, this.h, bMask); - } - notifyInputMethod(new Rectangle(x, y, w, h)); - */ } - private void setBoundsFields(int x, int y, int w, int h, int bMask) { - if ((bMask & NativeWindow.BOUNDS_NOSIZE) == 0) { - this.w = w; - this.h = h; + /** + * Sets the minimum size of the Component. + * + * @param minimumSize + * the new minimum size of the Component. + */ + public void setMinimumSize(Dimension minimumSize) { + Dimension oldMinimumSize; + toolkit.lockAWT(); + try { + oldMinimumSize = this.minimumSize; + if (oldMinimumSize != null) { + oldMinimumSize = oldMinimumSize.getSize(); + } + if (this.minimumSize == null) { + if (minimumSize != null) { + this.minimumSize = new Dimension(minimumSize); + } + } else { + if (minimumSize != null) { + this.minimumSize.setSize(minimumSize); + } else { + this.minimumSize = null; + } + } + } finally { + toolkit.unlockAWT(); } - if ((bMask & NativeWindow.BOUNDS_NOMOVE) == 0) { - this.x = x; - this.y = y; + firePropertyChange("minimumSize", oldMinimumSize, this.minimumSize); //$NON-NLS-1$ + toolkit.lockAWT(); + try { + // ???AWT: invalidateRealParent(); + } finally { + toolkit.unlockAWT(); } } - - public void resize(Dimension size) { - setSize(size.width, size.height); - } - - public int getWidth() { - return w; - } - public int getHeight() { - return h; + /** + * Sets the preferred size of the Component. + * + * @param preferredSize + * the new preferred size of the Component. + */ + public void setPreferredSize(Dimension preferredSize) { + Dimension oldPreferredSize; + toolkit.lockAWT(); + try { + oldPreferredSize = this.preferredSize; + if (oldPreferredSize != null) { + oldPreferredSize = oldPreferredSize.getSize(); + } + if (this.preferredSize == null) { + if (preferredSize != null) { + this.preferredSize = new Dimension(preferredSize); + } + } else { + if (preferredSize != null) { + this.preferredSize.setSize(preferredSize); + } else { + this.preferredSize = null; + } + } + } finally { + toolkit.unlockAWT(); + } + firePropertyChange("preferredSize", oldPreferredSize, this.preferredSize); //$NON-NLS-1$ + toolkit.lockAWT(); + try { + // ???AWT: invalidateRealParent(); + } finally { + toolkit.unlockAWT(); + } + } + + // ???AWT + /* + * RedrawManager getRedrawManager() { if (parent == null) { return null; } + * return parent.getRedrawManager(); } + */ + + /** + * Checks if is focusability explicitly set. + * + * @return true if component has a focusable peer. + */ + // ???AWT + /* + * boolean isPeerFocusable() { // The recommendations for Windows and Unix + * are that // Canvases, Labels, Panels, Scrollbars, ScrollPanes, Windows, + * // and lightweight Components have non-focusable peers, // and all other + * Components have focusable peers. if (this instanceof Canvas || this + * instanceof Label || this instanceof Panel || this instanceof Scrollbar || + * this instanceof ScrollPane || this instanceof Window || isLightweight()) + * { return false; } return true; } + */ + + /** + * @return true if focusability was explicitly set via a call to + * setFocusable() or via overriding isFocusable() or + * isFocusTraversable(). + */ + boolean isFocusabilityExplicitlySet() { + return calledSetFocusable || overridenIsFocusable; + } + + /** + * Paints the component and all of its subcomponents. + * + * @param g + * the Graphics to be used for painting. + */ + public void paintAll(Graphics g) { + toolkit.lockAWT(); + try { + paint(g); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Updates this Component. + * + * @param g + * the Graphics to be used for updating. + */ + public void update(Graphics g) { + toolkit.lockAWT(); + try { + if (!isLightweight() && !isPrepainter()) { + g.setColor(getBackground()); + g.fillRect(0, 0, w, h); + g.setColor(getForeground()); + } + paint(g); + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Paints this component. + * + * @param g + * the Graphics to be used for painting. + */ + public void paint(Graphics g) { + toolkit.lockAWT(); + try { + // Just to nothing + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Prepares the component to be painted. + * + * @param g + * the Graphics to be used for painting. + */ + void prepaint(Graphics g) { + // Just to nothing. For overriding. + } + + /** + * Checks if is prepainter. + * + * @return true, if is prepainter. + */ + boolean isPrepainter() { + return false; + } + + /** + * Prepare4 hierarchy change. + */ + void prepare4HierarchyChange() { + if (hierarchyChangingCounter++ == 0) { + wasShowing = isShowing(); + wasDisplayable = isDisplayable(); + prepareChildren4HierarchyChange(); + } + } + + /** + * Prepare children4 hierarchy change. + */ + void prepareChildren4HierarchyChange() { + // To be inherited by Container + } + + // ???AWT + /* + * void finishHierarchyChange(Component changed, Container changedParent, + * int ancestorFlags) { if (--hierarchyChangingCounter == 0) { int + * changeFlags = ancestorFlags; if (wasShowing != isShowing()) { changeFlags + * |= HierarchyEvent.SHOWING_CHANGED; } if (wasDisplayable != + * isDisplayable()) { changeFlags |= HierarchyEvent.DISPLAYABILITY_CHANGED; + * } if (changeFlags > 0) { postEvent(new HierarchyEvent(this, + * HierarchyEvent.HIERARCHY_CHANGED, changed, changedParent, changeFlags)); + * } finishChildrenHierarchyChange(changed, changedParent, ancestorFlags); } + * } void finishChildrenHierarchyChange(Component changed, Container + * changedParent, int ancestorFlags) { // To be inherited by Container } + * void postHierarchyBoundsEvents(Component changed, int id) { postEvent(new + * HierarchyEvent(this, id, changed, null, 0)); } + */ + + /** + * Spread hierarchy bounds events. + * + * @param changed + * the changed. + * @param id + * the id. + */ + void spreadHierarchyBoundsEvents(Component changed, int id) { + // To be inherited by Container + } + + /** + * Dispatches an event to this component. + * + * @param e + * the Event. + */ + public final void dispatchEvent(AWTEvent e) { + // ???AWT + /* + * if (e.isConsumed()) { return; } if (e instanceof PaintEvent) { + * toolkit.dispatchAWTEvent(e); processPaintEvent((PaintEvent) e); + * return; } KeyboardFocusManager kfm = + * KeyboardFocusManager.getCurrentKeyboardFocusManager(); if + * (!e.dispatchedByKFM && kfm.dispatchEvent(e)) { return; } if (e + * instanceof KeyEvent) { KeyEvent ke = (KeyEvent) e; // consumes + * KeyEvent which represents a focus traversal key if + * (getFocusTraversalKeysEnabled()) { kfm.processKeyEvent(this, ke); if + * (ke.isConsumed()) { return; } } } if (inputMethodsEnabled && + * dispatchToIM && e.isPosted && dispatchEventToIM(e)) { return; } if + * (e.getID() == WindowEvent.WINDOW_ICONIFIED) { + * notifyInputMethod(null); } AWTEvent.EventDescriptor descriptor = + * toolkit.eventTypeLookup.getEventDescriptor(e); + * toolkit.dispatchAWTEvent(e); if (descriptor != null) { if + * (isEventEnabled(descriptor.eventMask) || + * (getListeners(descriptor.listenerType).length > 0)) { + * processEvent(e); } // input events can be consumed by user listeners: + * if (!e.isConsumed() && ((enabledAWTEvents & descriptor.eventMask) != + * 0)) { postprocessEvent(e, descriptor.eventMask); } } + * postDeprecatedEvent(e); + */ + } + + /** + * Post deprecated event. + * + * @param e + * the e. + */ + private void postDeprecatedEvent(AWTEvent e) { + if (deprecatedEventHandler) { + Event evt = e.getEvent(); + if (evt != null) { + postEvent(evt); + } + } + } + + /** + * Postprocess event. + * + * @param e + * the e. + * @param eventMask + * the event mask. + */ + void postprocessEvent(AWTEvent e, long eventMask) { + toolkit.lockAWT(); + try { + // call system listeners under AWT lock + if (eventMask == AWTEvent.FOCUS_EVENT_MASK) { + preprocessFocusEvent((FocusEvent)e); + } else if (eventMask == AWTEvent.KEY_EVENT_MASK) { + preprocessKeyEvent((KeyEvent)e); + } else if (eventMask == AWTEvent.MOUSE_EVENT_MASK) { + preprocessMouseEvent((MouseEvent)e); + } else if (eventMask == AWTEvent.MOUSE_MOTION_EVENT_MASK) { + preprocessMouseMotionEvent((MouseEvent)e); + } else if (eventMask == AWTEvent.COMPONENT_EVENT_MASK) { + preprocessComponentEvent((ComponentEvent)e); + } else if (eventMask == AWTEvent.MOUSE_WHEEL_EVENT_MASK) { + preprocessMouseWheelEvent((MouseWheelEvent)e); + } else if (eventMask == AWTEvent.INPUT_METHOD_EVENT_MASK) { + preprocessInputMethodEvent((InputMethodEvent)e); + } + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Preprocess input method event. + * + * @param e + * the e. + */ + private void preprocessInputMethodEvent(InputMethodEvent e) { + processInputMethodEventImpl(e, inputMethodListeners.getSystemListeners()); + } + + /** + * Preprocess mouse wheel event. + * + * @param e + * the e. + */ + private void preprocessMouseWheelEvent(MouseWheelEvent e) { + processMouseWheelEventImpl(e, mouseWheelListeners.getSystemListeners()); + } + + /** + * Process mouse wheel event impl. + * + * @param e + * the e. + * @param c + * the c. + */ + private void processMouseWheelEventImpl(MouseWheelEvent e, Collection c) { + for (MouseWheelListener listener : c) { + switch (e.getID()) { + case MouseEvent.MOUSE_WHEEL: + listener.mouseWheelMoved(e); + break; + } + } + } + + /** + * Preprocess component event. + * + * @param e + * the e. + */ + private void preprocessComponentEvent(ComponentEvent e) { + processComponentEventImpl(e, componentListeners.getSystemListeners()); + } + + /** + * Preprocess mouse motion event. + * + * @param e + * the e. + */ + void preprocessMouseMotionEvent(MouseEvent e) { + processMouseMotionEventImpl(e, mouseMotionListeners.getSystemListeners()); + } + + /** + * Preprocess mouse event. + * + * @param e + * the e + */ + void preprocessMouseEvent(MouseEvent e) { + processMouseEventImpl(e, mouseListeners.getSystemListeners()); + } + + /** + * Preprocess key event. + * + * @param e + * the e. + */ + void preprocessKeyEvent(KeyEvent e) { + processKeyEventImpl(e, keyListeners.getSystemListeners()); + } + + /** + * Preprocess focus event. + * + * @param e + * the e. + */ + void preprocessFocusEvent(FocusEvent e) { + processFocusEventImpl(e, focusListeners.getSystemListeners()); + } + + /** + * Processes AWTEvent occurred on this component. + * + * @param e + * the AWTEvent. + */ + protected void processEvent(AWTEvent e) { + long eventMask = toolkit.eventTypeLookup.getEventMask(e); + if (eventMask == AWTEvent.COMPONENT_EVENT_MASK) { + processComponentEvent((ComponentEvent)e); + } else if (eventMask == AWTEvent.FOCUS_EVENT_MASK) { + processFocusEvent((FocusEvent)e); + } else if (eventMask == AWTEvent.KEY_EVENT_MASK) { + processKeyEvent((KeyEvent)e); + } else if (eventMask == AWTEvent.MOUSE_EVENT_MASK) { + processMouseEvent((MouseEvent)e); + } else if (eventMask == AWTEvent.MOUSE_WHEEL_EVENT_MASK) { + processMouseWheelEvent((MouseWheelEvent)e); + } else if (eventMask == AWTEvent.MOUSE_MOTION_EVENT_MASK) { + processMouseMotionEvent((MouseEvent)e); + } else if (eventMask == AWTEvent.HIERARCHY_EVENT_MASK) { + processHierarchyEvent((HierarchyEvent)e); + } else if (eventMask == AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) { + processHierarchyBoundsEvent((HierarchyEvent)e); + } else if (eventMask == AWTEvent.INPUT_METHOD_EVENT_MASK) { + processInputMethodEvent((InputMethodEvent)e); + } + } + + /** + * Gets an array of all listener's objects based on the specified listener + * type and registered to this Component. + * + * @param listenerType + * the listener type. + * @return an array of all listener's objects based on the specified + * listener type and registered to this Component. + */ + @SuppressWarnings("unchecked") + public T[] getListeners(Class listenerType) { + if (ComponentListener.class.isAssignableFrom(listenerType)) { + return (T[])getComponentListeners(); + } else if (FocusListener.class.isAssignableFrom(listenerType)) { + return (T[])getFocusListeners(); + } else if (HierarchyBoundsListener.class.isAssignableFrom(listenerType)) { + return (T[])getHierarchyBoundsListeners(); + } else if (HierarchyListener.class.isAssignableFrom(listenerType)) { + return (T[])getHierarchyListeners(); + } else if (InputMethodListener.class.isAssignableFrom(listenerType)) { + return (T[])getInputMethodListeners(); + } else if (KeyListener.class.isAssignableFrom(listenerType)) { + return (T[])getKeyListeners(); + } else if (MouseWheelListener.class.isAssignableFrom(listenerType)) { + return (T[])getMouseWheelListeners(); + } else if (MouseMotionListener.class.isAssignableFrom(listenerType)) { + return (T[])getMouseMotionListeners(); + } else if (MouseListener.class.isAssignableFrom(listenerType)) { + return (T[])getMouseListeners(); + } else if (PropertyChangeListener.class.isAssignableFrom(listenerType)) { + return (T[])getPropertyChangeListeners(); + } + return (T[])Array.newInstance(listenerType, 0); + } + + /** + * Process paint event. + * + * @param event + * the event. + */ + private void processPaintEvent(PaintEvent event) { + if (redrawManager == null) { + return; + } + Rectangle clipRect = event.getUpdateRect(); + if ((clipRect.width <= 0) || (clipRect.height <= 0)) { + return; + } + Graphics g = getGraphics(); + if (g == null) { + return; + } + initGraphics(g, event); + if (!getIgnoreRepaint()) { + if (event.getID() == PaintEvent.PAINT) { + paint(g); + } else { + update(g); + } + } + g.dispose(); + } + + /** + * Inits the graphics. + * + * @param g + * the g. + * @param e + * the e. + */ + void initGraphics(Graphics g, PaintEvent e) { + Rectangle clip = e.getUpdateRect(); + if (clip instanceof ClipRegion) { + g.setClip(((ClipRegion)clip).getClip()); + } else { + g.setClip(clip); + } + if (isPrepainter()) { + prepaint(g); + } else if (!isLightweight() && (e.getID() == PaintEvent.PAINT)) { + g.setColor(getBackground()); + g.fillRect(0, 0, w, h); + } + g.setFont(getFont()); + g.setColor(getForeground()); + } + + /** + * Enables the events with the specified event mask to be delivered to this + * component. + * + * @param eventsToEnable + * the events mask which specifies the types of events to enable. + */ + protected final void enableEvents(long eventsToEnable) { + toolkit.lockAWT(); + try { + enabledEvents |= eventsToEnable; + deprecatedEventHandler = false; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Enable awt events. + * + * @param eventsToEnable + * the events to enable. + */ + private void enableAWTEvents(long eventsToEnable) { + enabledAWTEvents |= eventsToEnable; + } + + /** + * Disables the events with types specified by the specified event mask from + * being delivered to this component. + * + * @param eventsToDisable + * the event mask specifying the event types. + */ + protected final void disableEvents(long eventsToDisable) { + toolkit.lockAWT(); + try { + enabledEvents &= ~eventsToDisable; + } finally { + toolkit.unlockAWT(); + } + } + + /* + * For use in MouseDispatcher only. Really it checks not only mouse events. + */ + /** + * Checks if is mouse event enabled. + * + * @param eventMask + * the event mask. + * @return true, if is mouse event enabled. + */ + boolean isMouseEventEnabled(long eventMask) { + return (isEventEnabled(eventMask) || (enabledAWTEvents & eventMask) != 0); + } + + /** + * Checks if is event enabled. + * + * @param eventMask + * the event mask. + * @return true, if is event enabled. + */ + boolean isEventEnabled(long eventMask) { + return ((enabledEvents & eventMask) != 0); + } + + /** + * Enables or disables input method support for this component. + * + * @param enable + * true to enable input method support, false to disable it. + */ + public void enableInputMethods(boolean enable) { + toolkit.lockAWT(); + try { + if (!enable) { + removeNotifyInputContext(); + } + inputMethodsEnabled = enable; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets an array of all component's listeners registered for this component. + * + * @return an array of all component's listeners registered for this + * component. + */ + public ComponentListener[] getComponentListeners() { + return componentListeners.getUserListeners(new ComponentListener[0]); + } + + /** + * Adds the specified component listener to the Component for receiving + * component's event. + * + * @param l + * the ComponentListener. + */ + public void addComponentListener(ComponentListener l) { + componentListeners.addUserListener(l); + } + + /** + * Removes the component listener registered for this Component. + * + * @param l + * the ComponentListener. + */ + public void removeComponentListener(ComponentListener l) { + componentListeners.removeUserListener(l); + } + + /** + * Processes a component event that has occurred on this component by + * dispatching them to any registered ComponentListener objects. + * + * @param e + * the ComponentEvent. + */ + protected void processComponentEvent(ComponentEvent e) { + processComponentEventImpl(e, componentListeners.getUserListeners()); + } + + /** + * Process component event impl. + * + * @param e + * the e. + * @param c + * the c. + */ + private void processComponentEventImpl(ComponentEvent e, Collection c) { + for (ComponentListener listener : c) { + switch (e.getID()) { + case ComponentEvent.COMPONENT_HIDDEN: + listener.componentHidden(e); + break; + case ComponentEvent.COMPONENT_MOVED: + listener.componentMoved(e); + break; + case ComponentEvent.COMPONENT_RESIZED: + listener.componentResized(e); + break; + case ComponentEvent.COMPONENT_SHOWN: + listener.componentShown(e); + break; + } + } + } + + /** + * Gets an array of focus listeners registered for this Component. + * + * @return the array of focus listeners registered for this Component. + */ + public FocusListener[] getFocusListeners() { + return focusListeners.getUserListeners(new FocusListener[0]); + } + + /** + * Adds the specified focus listener to the Component for receiving focus + * events. + * + * @param l + * the FocusListener. + */ + public void addFocusListener(FocusListener l) { + focusListeners.addUserListener(l); + } + + /** + * Adds the awt focus listener. + * + * @param l + * the l. + */ + void addAWTFocusListener(FocusListener l) { + enableAWTEvents(AWTEvent.FOCUS_EVENT_MASK); + focusListeners.addSystemListener(l); + } + + /** + * Removes the focus listener registered for this Component. + * + * @param l + * the FocusListener. + */ + public void removeFocusListener(FocusListener l) { + focusListeners.removeUserListener(l); + } + + /** + * Processes a FocusEvent that has occurred on this component by dispatching + * it to the registered listeners. + * + * @param e + * the FocusEvent. + */ + protected void processFocusEvent(FocusEvent e) { + processFocusEventImpl(e, focusListeners.getUserListeners()); + } + + /** + * Process focus event impl. + * + * @param e + * the e. + * @param c + * the c. + */ + private void processFocusEventImpl(FocusEvent e, Collection c) { + for (FocusListener listener : c) { + switch (e.getID()) { + case FocusEvent.FOCUS_GAINED: + listener.focusGained(e); + break; + case FocusEvent.FOCUS_LOST: + listener.focusLost(e); + break; + } + } + } + + /** + * Gets an array of registered HierarchyListeners for this Component. + * + * @return an array of registered HierarchyListeners for this Component. + */ + public HierarchyListener[] getHierarchyListeners() { + return hierarchyListeners.getUserListeners(new HierarchyListener[0]); + } + + /** + * Adds the specified hierarchy listener. + * + * @param l + * the HierarchyListener. + */ + public void addHierarchyListener(HierarchyListener l) { + hierarchyListeners.addUserListener(l); + } + + /** + * Removes the hierarchy listener registered for this component. + * + * @param l + * the HierarchyListener. + */ + public void removeHierarchyListener(HierarchyListener l) { + hierarchyListeners.removeUserListener(l); + } + + /** + * Processes a hierarchy event that has occurred on this component by + * dispatching it to the registered listeners. + * + * @param e + * the HierarchyEvent. + */ + protected void processHierarchyEvent(HierarchyEvent e) { + for (HierarchyListener listener : hierarchyListeners.getUserListeners()) { + switch (e.getID()) { + case HierarchyEvent.HIERARCHY_CHANGED: + listener.hierarchyChanged(e); + break; + } + } + } + + /** + * Gets an array of HierarchyBoundsListener objects registered to this + * Component. + * + * @return an array of HierarchyBoundsListener objects. + */ + public HierarchyBoundsListener[] getHierarchyBoundsListeners() { + return hierarchyBoundsListeners.getUserListeners(new HierarchyBoundsListener[0]); + } + + /** + * Adds the specified hierarchy bounds listener. + * + * @param l + * the HierarchyBoundsListener. + */ + public void addHierarchyBoundsListener(HierarchyBoundsListener l) { + hierarchyBoundsListeners.addUserListener(l); + } + + /** + * Removes the hierarchy bounds listener registered for this Component. + * + * @param l + * the HierarchyBoundsListener. + */ + public void removeHierarchyBoundsListener(HierarchyBoundsListener l) { + hierarchyBoundsListeners.removeUserListener(l); + } + + /** + * Processes a hierarchy bounds event that has occurred on this component by + * dispatching it to the registered listeners. + * + * @param e + * the HierarchyBoundsEvent. + */ + protected void processHierarchyBoundsEvent(HierarchyEvent e) { + for (HierarchyBoundsListener listener : hierarchyBoundsListeners.getUserListeners()) { + switch (e.getID()) { + case HierarchyEvent.ANCESTOR_MOVED: + listener.ancestorMoved(e); + break; + case HierarchyEvent.ANCESTOR_RESIZED: + listener.ancestorResized(e); + break; + } + } + } + + /** + * Gets an array of the key listeners registered to the Component. + * + * @return an array of the key listeners registered to the Component. + */ + public KeyListener[] getKeyListeners() { + return keyListeners.getUserListeners(new KeyListener[0]); + } + + /** + * Adds the specified key listener. + * + * @param l + * the KeyListener. + */ + public void addKeyListener(KeyListener l) { + keyListeners.addUserListener(l); + } + + /** + * Adds the awt key listener. + * + * @param l + * the l. + */ + void addAWTKeyListener(KeyListener l) { + enableAWTEvents(AWTEvent.KEY_EVENT_MASK); + keyListeners.addSystemListener(l); + } + + /** + * Removes the key listener registered for this Component. + * + * @param l + * the KeyListener. + */ + public void removeKeyListener(KeyListener l) { + keyListeners.removeUserListener(l); + } + + /** + * Processes a key event that has occurred on this component by dispatching + * it to the registered listeners. + * + * @param e + * the KeyEvent. + */ + protected void processKeyEvent(KeyEvent e) { + processKeyEventImpl(e, keyListeners.getUserListeners()); + } + + /** + * Process key event impl. + * + * @param e + * the e. + * @param c + * the c. + */ + private void processKeyEventImpl(KeyEvent e, Collection c) { + for (KeyListener listener : c) { + switch (e.getID()) { + case KeyEvent.KEY_PRESSED: + listener.keyPressed(e); + break; + case KeyEvent.KEY_RELEASED: + listener.keyReleased(e); + break; + case KeyEvent.KEY_TYPED: + listener.keyTyped(e); + break; + } + } + } + + /** + * Gets an array of the mouse listeners registered to the Component. + * + * @return an array of the mouse listeners registered to the Component. + */ + public MouseListener[] getMouseListeners() { + return mouseListeners.getUserListeners(new MouseListener[0]); + } + + /** + * Adds the specified mouse listener. + * + * @param l + * the MouseListener. + */ + public void addMouseListener(MouseListener l) { + mouseListeners.addUserListener(l); + } + + /** + * Adds the awt mouse listener. + * + * @param l + * the l. + */ + void addAWTMouseListener(MouseListener l) { + enableAWTEvents(AWTEvent.MOUSE_EVENT_MASK); + mouseListeners.addSystemListener(l); + } + + /** + * Adds the awt mouse motion listener. + * + * @param l + * the l. + */ + void addAWTMouseMotionListener(MouseMotionListener l) { + enableAWTEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK); + mouseMotionListeners.addSystemListener(l); + } + + /** + * Adds the awt component listener. + * + * @param l + * the l. + */ + void addAWTComponentListener(ComponentListener l) { + enableAWTEvents(AWTEvent.COMPONENT_EVENT_MASK); + componentListeners.addSystemListener(l); + } + + /** + * Adds the awt input method listener. + * + * @param l + * the l. + */ + void addAWTInputMethodListener(InputMethodListener l) { + enableAWTEvents(AWTEvent.INPUT_METHOD_EVENT_MASK); + inputMethodListeners.addSystemListener(l); + } + + /** + * Adds the awt mouse wheel listener. + * + * @param l + * the l. + */ + void addAWTMouseWheelListener(MouseWheelListener l) { + enableAWTEvents(AWTEvent.MOUSE_WHEEL_EVENT_MASK); + mouseWheelListeners.addSystemListener(l); + } + + /** + * Removes the mouse listener registered for this Component. + * + * @param l + * the MouseListener. + */ + public void removeMouseListener(MouseListener l) { + mouseListeners.removeUserListener(l); + } + + /** + * Processes a mouse event that has occurred on this component by + * dispatching it to the registered listeners. + * + * @param e + * the MouseEvent. + */ + protected void processMouseEvent(MouseEvent e) { + processMouseEventImpl(e, mouseListeners.getUserListeners()); + } + + /** + * Process mouse event impl. + * + * @param e + * the e. + * @param c + * the c. + */ + private void processMouseEventImpl(MouseEvent e, Collection c) { + for (MouseListener listener : c) { + switch (e.getID()) { + case MouseEvent.MOUSE_CLICKED: + listener.mouseClicked(e); + break; + case MouseEvent.MOUSE_ENTERED: + listener.mouseEntered(e); + break; + case MouseEvent.MOUSE_EXITED: + listener.mouseExited(e); + break; + case MouseEvent.MOUSE_PRESSED: + listener.mousePressed(e); + break; + case MouseEvent.MOUSE_RELEASED: + listener.mouseReleased(e); + break; + } + } + } + + /** + * Process mouse motion event impl. + * + * @param e + * the e. + * @param c + * the c. + */ + private void processMouseMotionEventImpl(MouseEvent e, Collection c) { + for (MouseMotionListener listener : c) { + switch (e.getID()) { + case MouseEvent.MOUSE_DRAGGED: + listener.mouseDragged(e); + break; + case MouseEvent.MOUSE_MOVED: + listener.mouseMoved(e); + break; + } + } + } + + /** + * Gets an array of the mouse motion listeners registered to the Component. + * + * @return an array of the MouseMotionListeners registered to the Component. + */ + public MouseMotionListener[] getMouseMotionListeners() { + return mouseMotionListeners.getUserListeners(new MouseMotionListener[0]); + } + + /** + * Adds the specified mouse motion listener. + * + * @param l + * the MouseMotionListener. + */ + public void addMouseMotionListener(MouseMotionListener l) { + mouseMotionListeners.addUserListener(l); + } + + /** + * Removes the mouse motion listener registered for this component. + * + * @param l + * the MouseMotionListener. + */ + public void removeMouseMotionListener(MouseMotionListener l) { + mouseMotionListeners.removeUserListener(l); + } + + /** + * Processes a mouse motion event that has occurred on this component by + * dispatching it to the registered listeners. + * + * @param e + * the MouseEvent. + */ + protected void processMouseMotionEvent(MouseEvent e) { + processMouseMotionEventImpl(e, mouseMotionListeners.getUserListeners()); + } + + /** + * Gets an array of the mouse wheel listeners registered to the Component. + * + * @return an array of the MouseWheelListeners registered to the Component. + */ + public MouseWheelListener[] getMouseWheelListeners() { + return mouseWheelListeners.getUserListeners(new MouseWheelListener[0]); + } + + /** + * Adds the specified mouse wheel listener. + * + * @param l + * the MouseWheelListener. + */ + public void addMouseWheelListener(MouseWheelListener l) { + mouseWheelListeners.addUserListener(l); + } + + /** + * Removes the mouse wheel listener registered for this component. + * + * @param l + * the MouseWheelListener. + */ + public void removeMouseWheelListener(MouseWheelListener l) { + mouseWheelListeners.removeUserListener(l); + } + + /** + * Processes a mouse wheel event that has occurred on this component by + * dispatching it to the registered listeners. + * + * @param e + * the MouseWheelEvent. + */ + protected void processMouseWheelEvent(MouseWheelEvent e) { + processMouseWheelEventImpl(e, mouseWheelListeners.getUserListeners()); + } + + /** + * Gets an array of the InputMethodListener listeners registered to the + * Component. + * + * @return an array of the InputMethodListener listeners registered to the + * Component. + */ + public InputMethodListener[] getInputMethodListeners() { + return inputMethodListeners.getUserListeners(new InputMethodListener[0]); + } + + /** + * Adds the specified input method listener. + * + * @param l + * the InputMethodListener. + */ + public void addInputMethodListener(InputMethodListener l) { + inputMethodListeners.addUserListener(l); + } + + /** + * Removes the input method listener registered for this component. + * + * @param l + * the InputMethodListener. + */ + public void removeInputMethodListener(InputMethodListener l) { + inputMethodListeners.removeUserListener(l); + } + + /** + * Processes an input method event that has occurred on this component by + * dispatching it to the registered listeners. + * + * @param e + * the InputMethodEvent. + */ + protected void processInputMethodEvent(InputMethodEvent e) { + processInputMethodEventImpl(e, inputMethodListeners.getUserListeners()); + } + + /** + * Process input method event impl. + * + * @param e + * the e. + * @param c + * the c. + */ + private void processInputMethodEventImpl(InputMethodEvent e, Collection c) { + for (InputMethodListener listener : c) { + switch (e.getID()) { + case InputMethodEvent.CARET_POSITION_CHANGED: + listener.caretPositionChanged(e); + break; + case InputMethodEvent.INPUT_METHOD_TEXT_CHANGED: + listener.inputMethodTextChanged(e); + break; + } + } + } + + // ???AWT + /* + * public Point getMousePosition() throws HeadlessException { Point + * absPointerPos = MouseInfo.getPointerInfo().getLocation(); Window + * winUnderPtr = + * toolkit.dispatcher.mouseDispatcher.findWindowAt(absPointerPos); Point + * pointerPos = MouseDispatcher.convertPoint(null, absPointerPos, + * winUnderPtr); boolean isUnderPointer = false; if (winUnderPtr == null) { + * return null; } isUnderPointer = winUnderPtr.isComponentAt(this, + * pointerPos); if (isUnderPointer) { return + * MouseDispatcher.convertPoint(null, absPointerPos, this); } return null; } + */ + + /** + * Set native caret at the given position
+ * Note: this method takes AWT lock inside because it walks through the + * component hierarchy. + * + * @param x + * the x. + * @param y + * the y. + */ + void setCaretPos(final int x, final int y) { + Runnable r = new Runnable() { + public void run() { + toolkit.lockAWT(); + try { + setCaretPosImpl(x, y); + } finally { + toolkit.unlockAWT(); + } + } + }; + if (Thread.currentThread() instanceof EventDispatchThread) { + r.run(); + } else { + toolkit.getSystemEventQueueImpl().postEvent(new InvocationEvent(this, r)); + } + } + + /** + * This method should be called only at event dispatch thread. + * + * @param x + * the x. + * @param y + * the y. + */ + void setCaretPosImpl(int x, int y) { + Component c = this; + while ((c != null) && c.behaviour.isLightweight()) { + x += c.x; + y += c.y; + // ???AWT: c = c.getParent(); + } + if (c == null) { + return; + } + // ???AWT + /* + * if (c instanceof Window) { Insets insets = c.getNativeInsets(); x -= + * insets.left; y -= insets.top; } + * toolkit.getWindowFactory().setCaretPosition(x, y); + */ + } + + // to be overridden in standard components such as Button and List + /** + * Gets the default minimum size. + * + * @return the default minimum size. + */ + Dimension getDefaultMinimumSize() { + return null; + } + + // to be overridden in standard components such as Button and List + /** + * Gets the default preferred size. + * + * @return the default preferred size. + */ + Dimension getDefaultPreferredSize() { + return null; + } + + // to be overridden in standard components such as Button and List + /** + * Reset default size. + */ + void resetDefaultSize() { + } + + // ???AWT + ComponentBehavior createBehavior() { + // return new LWBehavior(this); + return new ComponentBehavior(){ + + @Override + public void addNotify() + { + // TODO: Implement this method + } + + @Override + public void setBounds(int x, int y, int w, int h, int bMask) + { + // TODO: Implement this method + } + + @Override + public void setVisible(boolean b) + { + // TODO: Implement this method + } + + @Override + public Graphics getGraphics(int translationX, int translationY, int width, int height) + { + // TODO: Implement this method + return AndroidGraphics2D.getInstance(); + } + + @Override + public NativeWindow getNativeWindow() + { + // TODO: Implement this method + return null; + } + + @Override + public boolean isLightweight() + { + // TODO: Implement this method + return false; + } + + @Override + public void onMove(int x, int y) + { + // TODO: Implement this method + } + + @Override + public boolean isOpaque() + { + // TODO: Implement this method + return false; + } + + @Override + public boolean isDisplayable() + { + // TODO: Implement this method + return true; + } + + @Override + public void setEnabled(boolean value) + { + // TODO: Implement this method + } + + @Override + public void removeNotify() + { + // TODO: Implement this method + } + + @Override + public void setZOrder(int newIndex, int oldIndex) + { + // TODO: Implement this method + } + + @Override + public boolean setFocus(boolean focus, Component opposite) + { + return false; + } + }; + } + + /** + * Gets the default background. + * + * @return the default background. + */ + Color getDefaultBackground() { + // ???AWT: return getWindowAncestor().getDefaultBackground(); + return getBackground(); + } + + /** + * Gets the default foreground. + * + * @return the default foreground. + */ + Color getDefaultForeground() { + // ???AWT return getWindowAncestor().getDefaultForeground(); + return getForeground(); + } + + /** + * Called when native resource for this component is created (for + * heavyweights only). + * + * @param win + * the win. + */ + void nativeWindowCreated(NativeWindow win) { + // to be overridden + } + + /** + * Determine the component's area hidden behind the windows that have higher + * Z-order, including windows of other applications. + * + * @param image + * the image. + * @param destLocation + * the dest location. + * @param destSize + * the dest size. + * @param source + * the source. + * @return the calculated region, or null if it cannot be determined. + */ + // ???AWT + /* + * MultiRectArea getObscuredRegion(Rectangle part) { if (!visible || parent + * == null || !parent.visible) { return null; } Rectangle r = new + * Rectangle(0, 0, w, h); if (part != null) { r = r.intersection(part); } if + * (r.isEmpty()) { return null; } r.translate(x, y); MultiRectArea ret = + * parent.getObscuredRegion(r); if (ret != null) { + * parent.addObscuredRegions(ret, this); ret.translate(-x, -y); + * ret.intersect(new Rectangle(0, 0, w, h)); } return ret; } + */ + + // ???AWT + /* + * private void readObject(ObjectInputStream stream) throws IOException, + * ClassNotFoundException { stream.defaultReadObject(); FieldsAccessor + * accessor = new FieldsAccessor(Component.class, this); + * accessor.set("toolkit", Toolkit.getDefaultToolkit()); //$NON-NLS-1$ + * accessor.set("behaviour", createBehavior()); //$NON-NLS-1$ + * accessor.set("componentLock", new Object()); // $NON-LOCK-1$ + * //$NON-NLS-1$ } + */ + + final void onDrawImage(Image image, Point destLocation, Dimension destSize, Rectangle source) { + ImageParameters imageParams; + if (updatedImages == null) { + updatedImages = new HashMap(); + } + imageParams = updatedImages.get(image); + if (imageParams == null) { + imageParams = new ImageParameters(); + updatedImages.put(image, imageParams); + } + imageParams.addDrawing(destLocation, destSize, source); + } + + public boolean imageUpdate(Image img, int infoflags, int x, int y, int w, int h) { + toolkit.lockAWT(); + try { + boolean done = false; + if ((infoflags & (ALLBITS | FRAMEBITS)) != 0) { + done = true; + } else if ((infoflags & SOMEBITS) != 0 && incrementalImageUpdate) { + done = true; + } + if (done) { + repaint(); + } + return (infoflags & (ABORT | ALLBITS)) == 0; + } finally { + toolkit.unlockAWT(); + } + } + + // ???AWT + /* + * private void invalidateRealParent() { Container realParent = + * getRealParent(); if ((realParent != null) && realParent.isValid()) { + * realParent.invalidate(); } } + */ + + /** + * The Class ImageParameters. + */ + private class ImageParameters { + + /** + * The drawing params. + */ + private final LinkedList drawingParams = new LinkedList(); + + /** + * The size. + */ + Dimension size = new Dimension(Component.this.w, Component.this.h); + + /** + * Adds the drawing. + * + * @param destLocation + * the dest location. + * @param destSize + * the dest size. + * @param source + * the source. + */ + void addDrawing(Point destLocation, Dimension destSize, Rectangle source) { + drawingParams.add(new DrawingParameters(destLocation, destSize, source)); + } + + /** + * Drawing parameters iterator. + * + * @return the iterator< drawing parameters>. + */ + Iterator drawingParametersIterator() { + return drawingParams.iterator(); + } + + /** + * The Class DrawingParameters. + */ + class DrawingParameters { + + /** + * The dest location. + */ + Point destLocation; + + /** + * The dest size. + */ + Dimension destSize; + + /** + * The source. + */ + Rectangle source; + + /** + * Instantiates a new drawing parameters. + * + * @param destLocation + * the dest location. + * @param destSize + * the dest size. + * @param source + * the source. + */ + DrawingParameters(Point destLocation, Dimension destSize, Rectangle source) { + this.destLocation = new Point(destLocation); + if (destSize != null) { + this.destSize = new Dimension(destSize); + } else { + this.destSize = null; + } + if (source != null) { + this.source = new Rectangle(source); + } else { + this.source = null; + } + } + } + } + + /** + * TextComponent support. + * + * @param e + * the e. + * @return true, if dispatch event to im. + */ + // ???AWT + /* + * private TextKit textKit = null; TextKit getTextKit() { return textKit; } + * void setTextKit(TextKit kit) { textKit = kit; } + */ + + /** + * TextField support. + */ + // ???AWT + /* + * private TextFieldKit textFieldKit = null; TextFieldKit getTextFieldKit() + * { return textFieldKit; } void setTextFieldKit(TextFieldKit kit) { + * textFieldKit = kit; } + */ + + /** + * Dispatches input & focus events to input method context. + * + * @param e + * event to pass to InputContext.dispatchEvent(). + * @return true if event was consumed by IM, false otherwise. + */ + private boolean dispatchEventToIM(AWTEvent e) { + InputContext ic = getInputContext(); + if (ic == null) { + return false; + } + int id = e.getID(); + boolean isInputEvent = ((id >= KeyEvent.KEY_FIRST) && (id <= KeyEvent.KEY_LAST)) + || ((id >= MouseEvent.MOUSE_FIRST) && (id <= MouseEvent.MOUSE_LAST)); + if (((id >= FocusEvent.FOCUS_FIRST) && (id <= FocusEvent.FOCUS_LAST)) || isInputEvent) { + ic.dispatchEvent(e); + } + return e.isConsumed(); } } - diff --git a/app/src/main/java/java/awt/ComponentBehavior.java b/app/src/main/java/java/awt/ComponentBehavior.java new file mode 100644 index 000000000..f4e8ffbf2 --- /dev/null +++ b/app/src/main/java/java/awt/ComponentBehavior.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Dmitry A. Durnev + * @version $Revision$ + */ +package java.awt; + +import org.apache.harmony.awt.wtk.NativeWindow; + +/** + * The interface of the helper object that encapsulates the difference + * between lightweight and heavyweight components. + */ +interface ComponentBehavior { + + void addNotify(); + + void setBounds(int x, int y, int w, int h, int bMask); + + void setVisible(boolean b); + + Graphics getGraphics(int translationX, int translationY, int width, int height); + + NativeWindow getNativeWindow(); + + boolean isLightweight(); + + void onMove(int x, int y); + + boolean isOpaque(); + + boolean isDisplayable(); + + void setEnabled(boolean value); + + void removeNotify(); + + void setZOrder(int newIndex, int oldIndex); + + boolean setFocus(boolean focus, Component opposite); +} diff --git a/app/src/main/java/java/awt/Composite.java b/app/src/main/java/java/awt/Composite.java new file mode 100644 index 000000000..d1730fef4 --- /dev/null +++ b/app/src/main/java/java/awt/Composite.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt; + +import java.awt.image.ColorModel; + +/** + * The Composite interface allows the methods to compose a draw primitive on the + * graphics area. The classes implementing this interface provides the rules and + * a method to create the context for a particular operation. + * + * @since Android 1.0 + */ +public interface Composite { + + /** + * Creates a CompositeContext which defines the encapsulated and optimized + * environment for a compositing operation. Several contexts can exist for a + * single Composite object. + * + * @param srcColorModel + * the source's ColorModel. + * @param dstColorModel + * the destination's ColorModel. + * @param hints + * the RenderingHints. + * @return the CompositeContext object. + */ + public CompositeContext createContext(ColorModel srcColorModel, ColorModel dstColorModel, + RenderingHints hints); + +} diff --git a/app/src/main/java/java/awt/CompositeContext.java b/app/src/main/java/java/awt/CompositeContext.java new file mode 100644 index 000000000..795640d42 --- /dev/null +++ b/app/src/main/java/java/awt/CompositeContext.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt; + +import java.awt.image.Raster; +import java.awt.image.WritableRaster; + +/** + * The CompositeContext interface specifies the encapsulated and optimized + * environment for a compositing operation. + * + * @since Android 1.0 + */ +public interface CompositeContext { + + /** + * Composes the two source Raster objects and places the result in the + * destination WritableRaster. + * + * @param src + * the source Raster. + * @param dstIn + * the destination Raster. + * @param dstOut + * the WritableRaster object where the result of composing + * operation is stored. + */ + public void compose(Raster src, Raster dstIn, WritableRaster dstOut); + + /** + * Releases resources allocated for a context. + */ + public void dispose(); + +} diff --git a/app/src/main/java/java/awt/Container.java b/app/src/main/java/java/awt/Container.java index a25fb7190..f73bf43b7 100644 --- a/app/src/main/java/java/awt/Container.java +++ b/app/src/main/java/java/awt/Container.java @@ -2,6 +2,18 @@ package java.awt; public class Container extends Component { + + @Override + public void remove(MenuComponent c) + { + } + + @Override + public Font getFont() + { + return Font.decode(null); + } + private java.util.List component = new java.util.ArrayList(); LayoutManager layoutMgr; @@ -144,11 +156,9 @@ public class Container extends Component while (!component.isEmpty()) { Component comp = component.remove(component.size()-1); - /* - if (peer != null) { - comp.removeNotify(); - } - */ + if (getPeer() != null) { + comp.removeNotify(); + } if (layoutMgr != null) { layoutMgr.removeLayoutComponent(comp); } @@ -174,8 +184,9 @@ public class Container extends Component if (peer != null && layoutMgr == null && isVisible()) { updateCursorImmediately(); } - */ + invalidateIfValid(); + */ } public void remove(Component comp) { diff --git a/app/src/main/java/java/awt/Cursor.java b/app/src/main/java/java/awt/Cursor.java index 7fc31cf61..0a0cc8498 100644 --- a/app/src/main/java/java/awt/Cursor.java +++ b/app/src/main/java/java/awt/Cursor.java @@ -130,11 +130,11 @@ public class Cursor implements Serializable { * The Constant predefinedNames. */ static final String[] predefinedNames = { - "Default", "Crosshair", "Text", "Wait", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ - "Southwest Resize", "Southeast Resize", //$NON-NLS-1$ //$NON-NLS-2$ - "Northwest Resize", "Northeast Resize", //$NON-NLS-1$ //$NON-NLS-2$ - "North Resize", "South Resize", "West Resize", "East Resize", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ - "Hand", "Move" //$NON-NLS-1$ //$NON-NLS-2$ + "Default", "Crosshair", "Text", "Wait", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + "Southwest Resize", "Southeast Resize", //$NON-NLS-1$ //$NON-NLS-2$ + "Northwest Resize", "Northeast Resize", //$NON-NLS-1$ //$NON-NLS-2$ + "North Resize", "South Resize", "West Resize", "East Resize", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + "Hand", "Move" //$NON-NLS-1$ //$NON-NLS-2$ }; @@ -142,8 +142,8 @@ public class Cursor implements Serializable { * The predefined set of cursors. */ protected static Cursor[] predefined = { - new Cursor(DEFAULT_CURSOR), null, null, null, null, null, null, null, null, null, null, - null, null, null + new Cursor(DEFAULT_CURSOR), null, null, null, null, null, null, null, null, null, null, + null, null, null }; /** @@ -165,7 +165,7 @@ public class Cursor implements Serializable { /** * The native cursor. */ - private transient NativeCursor nativeCursor; + private transient NativeCursor nativeCursor; /** * The exact point on the cursor image that indicates which point the cursor @@ -363,7 +363,7 @@ public class Cursor implements Serializable { String sep = File.separator; String cursorsDir = "lib" + sep + "images" + sep + "cursors"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ String cursorsAbsDir = System.getProperty("java.home") + sep + //$NON-NLS-1$ - cursorsDir; + cursorsDir; String cursorPropsFileName = "cursors.properties"; //$NON-NLS-1$ String cursorPropsFullFileName = (cursorsAbsDir + sep + cursorPropsFileName); cursorProps = new Properties(); @@ -372,9 +372,9 @@ public class Cursor implements Serializable { } catch (FileNotFoundException e) { // awt.142=Exception: class {0} {1} occurred while loading: {2} throw new AWTException(Messages.getString("awt.142",//$NON-NLS-1$ - new Object[] { - e.getClass(), e.getMessage(), cursorPropsFullFileName - })); + new Object[] { + e.getClass(), e.getMessage(), cursorPropsFullFileName + })); } catch (IOException e) { throw new AWTException(e.getMessage()); } @@ -405,13 +405,13 @@ public class Cursor implements Serializable { NativeCursor getNativeCursor() { if (nativeCursor != null) { return nativeCursor; - }/* - Toolkit toolkit = Toolkit.getDefaultToolkit(); - if (type != CUSTOM_CURSOR) { - nativeCursor = toolkit.createNativeCursor(type); - } else { - nativeCursor = toolkit.createCustomNativeCursor(image, hotSpot, name); - }*/ + } + Toolkit toolkit = Toolkit.getDefaultToolkit(); + if (type != CUSTOM_CURSOR) { + nativeCursor = toolkit.createNativeCursor(type); + } else { + nativeCursor = toolkit.createCustomNativeCursor(image, hotSpot, name); + } return nativeCursor; } diff --git a/app/src/main/java/java/awt/Desktop.java b/app/src/main/java/java/awt/Desktop.java index b4a20ff0d..22e1c1ee3 100644 --- a/app/src/main/java/java/awt/Desktop.java +++ b/app/src/main/java/java/awt/Desktop.java @@ -13,52 +13,45 @@ import java.awt.mod.*; public class Desktop { - private MainActivity currentActivity; + private Activity currentActivity; public enum Action { BROWSE, EDIT, MAIL, OPEN, PRINT } - private DesktopPeer peer; + // private DesktopPeer peer; public Desktop() { - peer = Toolkit.getDefaultToolkit().createDesktopPeer(); - try - { + // peer = Toolkit.getDefaultToolkit().createDesktopPeer(); + try { if (currentActivity == null) currentActivity = ModdingKit.getCurrentActivity(); - } - catch (Exception e) - { + } catch (Exception e) { throw new RuntimeException(e); } } - public static Desktop getDesktop() - { + public static Desktop getDesktop() { return new Desktop(); } - public static boolean isDesktopSupported() - { + public static boolean isDesktopSupported() { return true; } - public boolean isSupported(Action action) - { + public boolean isSupported(Action action) { return true; } - public void browse(URI uri) - { + public void browse(URI uri) { try { URL url = uri.toURL(); if(url.toString().startsWith("file:")){ String fPath = url.toString().replace("file:", ""); - Log.d("MineDebug:java.awt.Desktop", "Browse folder: " + fPath); + System.out.println("PojavLauncher:java.awt.Desktop: Browse folder: " + fPath); // Current not implemented } else{ - Log.d("MineDebug:java.awt.Desktop", "Browse URL: " + url.toString()); + System.out.println("PojavLauncher:java.awt.Desktop: Browse URL: " + url.toString()); if (!url.toString().startsWith("http://") && !url.toString().startsWith("https://")){ url = new URL("http://" + url.toString()); } diff --git a/app/src/main/java/java/awt/Dispatcher.java b/app/src/main/java/java/awt/Dispatcher.java new file mode 100644 index 000000000..d457af460 --- /dev/null +++ b/app/src/main/java/java/awt/Dispatcher.java @@ -0,0 +1,723 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov, Dmitry A. Durnev + * @version $Revision$ + */ +package java.awt; + +import java.awt.event.ComponentEvent; +import java.awt.event.FocusEvent; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.event.PaintEvent; +import java.awt.event.WindowEvent; + +import org.apache.harmony.awt.internal.nls.Messages; +import org.apache.harmony.awt.wtk.NativeEvent; +import org.apache.harmony.awt.wtk.NativeWindow; + + +/** + * Helper package-private class for managing lightweight components & + * dispatching events from heavyweight source + */ +class Dispatcher { + + //???AWT: final PopupDispatcher popupDispatcher = new PopupDispatcher(); + + //???AWT: final FocusDispatcher focusDispatcher; + + final MouseGrabManager mouseGrabManager = new MouseGrabManager(); + + final MouseDispatcher mouseDispatcher; + + private final ComponentDispatcher componentDispatcher = new ComponentDispatcher(); + + private final KeyDispatcher keyDispatcher = new KeyDispatcher(); + + private final Toolkit toolkit; + + int clickInterval = 250; + + /** + * @param toolkit - AWT toolkit + */ + Dispatcher(Toolkit toolkit) { + this.toolkit = toolkit; + + //???AWT: focusDispatcher = new FocusDispatcher(toolkit); + mouseDispatcher = new MouseDispatcher(mouseGrabManager, toolkit); + } + + /** + * Dispatch native event: produce appropriate AWT events, + * update component's fields when needed + * @param event - native event to dispatch + * @return - true means default processing by OS is not needed + */ + public boolean onEvent(NativeEvent event) { + int eventId = event.getEventId(); + + if (eventId == NativeEvent.ID_CREATED) { + return toolkit.onWindowCreated(event.getWindowId()); + } else if (eventId == NativeEvent.ID_MOUSE_GRAB_CANCELED) { + return mouseGrabManager.onGrabCanceled(); + //???AWT +// } else if (popupDispatcher.onEvent(event)) { +// return false; + } else { + Component src = toolkit.getComponentById(event.getWindowId()); + + if (src != null) { + if (((eventId >= ComponentEvent.COMPONENT_FIRST) && (eventId <= ComponentEvent.COMPONENT_LAST)) + || ((eventId >= WindowEvent.WINDOW_FIRST) && (eventId <= WindowEvent.WINDOW_LAST)) + || (eventId == NativeEvent.ID_INSETS_CHANGED) + || (eventId == NativeEvent.ID_BOUNDS_CHANGED) + || (eventId == NativeEvent.ID_THEME_CHANGED)) { + return componentDispatcher.dispatch(src, event); + } else if ((eventId >= MouseEvent.MOUSE_FIRST) + && (eventId <= MouseEvent.MOUSE_LAST)) { + return mouseDispatcher.dispatch(src, event); + } else if (eventId == PaintEvent.PAINT) { + //???AWT: src.redrawManager.addPaintRegion(src, event.getClipRects()); + return true; + } + } + if ((eventId >= FocusEvent.FOCUS_FIRST) + && (eventId <= FocusEvent.FOCUS_LAST)) { + + //???AWT: return focusDispatcher.dispatch(src, event); + return false; + } else if ((eventId >= KeyEvent.KEY_FIRST) + && (eventId <= KeyEvent.KEY_LAST)) { + return keyDispatcher.dispatch(src, event); + } + } + + return false; + } + + /** + * The dispatcher of native events that affect + * component's state or bounds + */ + final class ComponentDispatcher { + + /** + * Handle native event that affects component's state or bounds + * @param src - the component updated by the event + * @param event - the native event + * @return - as in Dispatcher.onEvent() + * @see Dispatcher#onEvent(NativeEvent) + */ + boolean dispatch(Component src, NativeEvent event) { + int id = event.getEventId(); + + if ((id == NativeEvent.ID_INSETS_CHANGED) + || (id == NativeEvent.ID_THEME_CHANGED)) { + return dispatchInsets(event, src); + } else if ((id >= WindowEvent.WINDOW_FIRST) + && (id <= WindowEvent.WINDOW_LAST)) { + return dispatchWindow(event, src); + } else { + return dispatchPureComponent(event, src); + } + } + + /** + * Handle the change of top-level window's native decorations + * @param event - the native event + * @param src - the component updated by the event + * @return - as in Dispatcher.onEvent() + * @see Dispatcher#onEvent(NativeEvent) + */ + boolean dispatchInsets(NativeEvent event, Component src) { + //???AWT + /* + if (src instanceof Window) { + ((Window) src).setNativeInsets(event.getInsets()); + } + */ + return false; + } + + /** + * Handle the change of top-level window's state + * @param event - the native event + * @param src - the component updated by the event + * @return - as in Dispatcher.onEvent() + * @see Dispatcher#onEvent(NativeEvent) + */ + boolean dispatchWindow(NativeEvent event, Component src) { + //???AWT + /* + Window window = (Window) src; + int id = event.getEventId(); + + if (id == WindowEvent.WINDOW_CLOSING) { + toolkit.getSystemEventQueueImpl().postEvent( + new WindowEvent(window, WindowEvent.WINDOW_CLOSING)); + + return true; + } else if (id == WindowEvent.WINDOW_STATE_CHANGED) { + if (window instanceof Frame) { + ((Frame) window) + .updateExtendedState(event.getWindowState()); + } + } + */ + + return false; + } + + /** + * Handle the change of component's size and/or position + * @param event - the native event + * @param src - the component updated by the event + * @return - as in Dispatcher.onEvent() + * @see Dispatcher#onEvent(NativeEvent) + */ + private boolean dispatchPureComponent(NativeEvent event, Component src) { + Rectangle rect = event.getWindowRect(); + Point loc = rect.getLocation(); + int mask; + + switch (event.getEventId()) { + case NativeEvent.ID_BOUNDS_CHANGED: + mask = 0; + break; + case ComponentEvent.COMPONENT_MOVED: + mask = NativeWindow.BOUNDS_NOSIZE; + break; + case ComponentEvent.COMPONENT_RESIZED: + mask = NativeWindow.BOUNDS_NOMOVE; + break; + default: + // awt.12E=Unknown component event id. + throw new RuntimeException(Messages.getString("awt.12E")); //$NON-NLS-1$ + } + + //???AWT + /* + if (!(src instanceof Window)) { + Component compTo = src.getParent(); + Component compFrom = src.getHWAncestor(); + + if ((compTo != null) && (compFrom != null)) { + loc = MouseDispatcher.convertPoint(compFrom, loc, compTo); + } + } else { + int windowState = event.getWindowState(); + + if ((windowState >= 0) && (src instanceof Frame)) { + ((Frame) src).updateExtendedState(windowState); + } + } + src.setBounds(loc.x, loc.y, rect.width, rect.height, mask, false); + */ + + return false; + } + + } + + /** + * The dispatcher of the keyboard events + */ + final class KeyDispatcher { + + /** + * Handle the keyboard event using the KeyboardFocusManager + * @param src - the component receiving the event + * @param event - the native event + * @return - as in Dispatcher.onEvent() + * @see Dispatcher#onEvent(NativeEvent) + */ + boolean dispatch(Component src, NativeEvent event) { + int id = event.getEventId(); + int modifiers = event.getInputModifiers(); + int location = event.getKeyLocation(); + int code = event.getVKey(); + StringBuffer chars = event.getKeyChars(); + int charsLength = chars.length(); + long time = event.getTime(); + char keyChar = event.getLastChar(); + + //???AWT + /* + if (src == null) { + //retarget focus proxy key events to focusOwner: + Window focusProxyOwner = toolkit.getFocusProxyOwnerById(event + .getWindowId()); + if (focusProxyOwner == null) { + return false; + } + src = KeyboardFocusManager.actualFocusOwner; + } + */ + + EventQueue eventQueue = toolkit.getSystemEventQueueImpl(); + + if (src != null) { + eventQueue.postEvent(new KeyEvent(src, id, time, modifiers, + code, keyChar, location)); + // KEY_TYPED goes after KEY_PRESSED + if (id == KeyEvent.KEY_PRESSED) { + for (int i = 0; i < charsLength; i++) { + keyChar = chars.charAt(i); + if (keyChar != KeyEvent.CHAR_UNDEFINED) { + eventQueue.postEvent(new KeyEvent(src, + KeyEvent.KEY_TYPED, time, modifiers, + KeyEvent.VK_UNDEFINED, keyChar, + KeyEvent.KEY_LOCATION_UNKNOWN)); + } + } + } + } + + return false; + } + + } + + /** + * Retargets the mouse events to the grab owner when mouse is grabbed, + * grab and ungrab mouse when mouse buttons are pressed and released + */ + + static final class MouseGrabManager { + + /** + * The top-level window holding the mouse grab + * that was explicitly started by startGrab() method + */ + //???AWT: private Window nativeGrabOwner = null; + /** + * The component that owns the synthetic + * mouse grab while at least one of the + * mouse buttons is pressed + */ + private Component syntheticGrabOwner = null; + + /** + * Previous value of syntheticGrabOwner + */ + private Component lastSyntheticGrabOwner = null; + + /** + * Number of mouse buttons currently pressed + */ + private int syntheticGrabDepth = 0; + + /** + * The callback to be called when the explicit mouse grab ends + */ + private Runnable whenCanceled; + + /** + * Explicitly start the mouse grab + * @param grabWindow - the window that will own the grab + * @param whenCanceled - the callback to call when the grab ends. + * This parameter can be null + */ + //???AWT + /* + void startGrab(Window grabWindow, Runnable whenCanceled) { + + if (nativeGrabOwner != null) { + // awt.12F=Attempt to start nested mouse grab + throw new RuntimeException(Messages.getString("awt.12F")); //$NON-NLS-1$ + } + + NativeWindow win = grabWindow.getNativeWindow(); + if (win == null) { + // awt.130=Attempt to grab mouse in not displayable window + throw new RuntimeException(Messages.getString("awt.130")); //$NON-NLS-1$ + } + + nativeGrabOwner = grabWindow; + this.whenCanceled = whenCanceled; + win.grabMouse(); + } + */ + + /** + * Ends the explicit mouse grab. If the non-null callback was provided + * in the startGrab() method, this callback is called + */ + void endGrab() { + //???AWT + /* + if (nativeGrabOwner == null) { + return; + } + + Window grabWindow = nativeGrabOwner; + nativeGrabOwner = null; + NativeWindow win = grabWindow.getNativeWindow(); + + if (win != null) { + win.ungrabMouse(); + if (whenCanceled != null) { + whenCanceled.run(); + whenCanceled = null; + } + } + */ + } + + /** + * Ends both explicit and synthetic grans + * @return - always returns false + */ + boolean onGrabCanceled() { + endGrab(); + resetSyntheticGrab(); + + return false; + } + + /** + * Starts the synthetic mouse grab, increases the counter + * of currently pressed mouse buttons + * @param source - the component where mouse press event occured + * @return - the component that owns the synthetic grab + */ + Component onMousePressed(Component source) { + if (syntheticGrabDepth == 0) { + syntheticGrabOwner = source; + lastSyntheticGrabOwner = source; + } + syntheticGrabDepth++; + + return syntheticGrabOwner; + } + + /** + * Decreases the counter of currently pressed mouse buttons, + * ends the synthetic mouse grab, when this counter becomes zero + * @param source - the component where mouse press event occured + * @return - the component that owns the synthetic grab, + * or source parameter if mouse grab was released + */ + Component onMouseReleased(Component source) { + Component ret = source; + + //???AWT + /* + if (syntheticGrabOwner != null && nativeGrabOwner == null) { + ret = syntheticGrabOwner; + } + */ + syntheticGrabDepth--; + if (syntheticGrabDepth <= 0) { + resetSyntheticGrab(); + lastSyntheticGrabOwner = null; + } + + return ret; + } + + /** + * Update the state of synthetic ouse gram + * when the mouse is moved/dragged + * @param event - the native event + */ + void preprocessEvent(NativeEvent event) { + int id = event.getEventId(); + switch (id) { + case MouseEvent.MOUSE_MOVED: + if (syntheticGrabOwner != null) { + syntheticGrabOwner = null; + syntheticGrabDepth = 0; + } + if (lastSyntheticGrabOwner != null) { + lastSyntheticGrabOwner = null; + } + case MouseEvent.MOUSE_DRAGGED: + if (syntheticGrabOwner == null + && lastSyntheticGrabOwner != null) { + syntheticGrabOwner = lastSyntheticGrabOwner; + syntheticGrabDepth = 0; + int mask = event.getInputModifiers(); + syntheticGrabDepth += (mask & InputEvent.BUTTON1_DOWN_MASK) != 0 ? 1 + : 0; + syntheticGrabDepth += (mask & InputEvent.BUTTON2_DOWN_MASK) != 0 ? 1 + : 0; + syntheticGrabDepth += (mask & InputEvent.BUTTON3_DOWN_MASK) != 0 ? 1 + : 0; + } + } + } + + /** + * @return the component that currently owns the synthetic grab + */ + Component getSyntheticGrabOwner() { + return syntheticGrabOwner; + } + + /** + * ends synthetic grab + */ + private void resetSyntheticGrab() { + syntheticGrabOwner = null; + syntheticGrabDepth = 0; + } + + } + + /** + * Dispatches native events related to the pop-up boxes + * (the non-component windows such as menus and drop lists) + */ +// final class PopupDispatcher { +// +// private PopupBox activePopup; +// +// private PopupBox underCursor; +// +// private final MouseGrab grab = new MouseGrab(); +// +// /** +// * Handles the mouse grab for pop-up boxes +// */ +// private final class MouseGrab { +// private int depth; +// +// private PopupBox owner; +// +// private final Point start = new Point(); +// +// /** +// * Starts the grab when mouse is pressed +// * @param src - the pop-up box where mouse event has occured +// * @param where - the mouse pointer location +// * @return - the grab owner +// */ +// PopupBox mousePressed(PopupBox src, Point where) { +// if (depth == 0) { +// owner = src; +// start.setLocation(where); +// } +// depth++; +// return owner; +// } +// +// /** +// * Ends the grab when all mousebuttons are released +// * @param src - the pop-up box where mouse event has occured +// * @param where - the mouse pointer location +// * @return - the grab owner, or src parameter if the grab has ended +// */ +// PopupBox mouseReleased(PopupBox src, Point where) { +// PopupBox ret = (owner != null) ? owner : src; +// if (depth == 0) { +// return ret; +// } +// depth--; +// if (depth == 0) { +// PopupBox tgt = owner; +// owner = null; +// if (tgt != null && src == null) { +// Point a = new Point(start); +// Point b = new Point(where); +// Point pos = tgt.getScreenLocation(); +// a.translate(-pos.x, -pos.y); +// b.translate(-pos.x, -pos.y); +// if (tgt.closeOnUngrab(a, b)) { +// return null; +// } +// } +// } +// return ret; +// } +// +// /** +// * Set the grab owner to null +// */ +// void reset() { +// depth = 0; +// owner = null; +// start.setLocation(0, 0); +// } +// +// /** +// * @return - the pop-up box currently owning the grab +// */ +// public PopupBox getOwner() { +// return owner; +// } +// } +// +// /** +// * Call the mouse event handler of the pop-up box +// * @param src - the pop-up box where the mouse event occured +// * @param eventId - the event ID, one of MouseEvent.MOUSE_* constants +// * @param where - the mouse pointer location +// * @param event - native event +// */ +// private void mouseEvent(PopupBox src, int eventId, Point where, +// NativeEvent event) { +// Point pos = src.getScreenLocation(); +// pos.setLocation(where.x - pos.x, where.y - pos.y); +// +// src.onMouseEvent(eventId, pos, event.getMouseButton(), event +// .getTime(), event.getInputModifiers(), event +// .getWheelRotation()); +// } +// +// /** +// * Handle the native event targeted by a pop-up box. This could be +// * paint event, mouse or keyboard event. +// * @param event - the native event +// * @return - false if the event was handled and doesn't +// * need the further processing; true when the further +// * processing is needed +// */ +// boolean onEvent(NativeEvent event) { +// PopupBox src = toolkit.getPopupBoxById(event.getWindowId()); +// int id = event.getEventId(); +// +// if ((id == PaintEvent.PAINT)) { +// if (src != null) { +// src.paint(event.getClipRects()); +// return true; +// } +// Component c = toolkit.getComponentById(event.getWindowId()); +// if ((c != null) && (c instanceof Frame)) { +// ((Frame) c).paintMenuBar(event.getClipRects()); +// } +// return false; +// } +// +// if ((id >= MouseEvent.MOUSE_FIRST) && (id <= MouseEvent.MOUSE_LAST)) { +// Point where = event.getScreenPos(); +// +// if (src != underCursor) { +// if (underCursor != null) { +// mouseEvent(underCursor, MouseEvent.MOUSE_EXITED, where, +// event); +// } +// underCursor = src; +// if (underCursor != null) { +// mouseEvent(underCursor, MouseEvent.MOUSE_ENTERED, +// where, event); +// underCursor.setDefaultCursor(); +// } +// } +// if (id == MouseEvent.MOUSE_EXITED) { +// underCursor = null; +// } +// +// if ((activePopup == null) && (src == null || !src.isMenuBar())) { +// return false; +// } +// +// if (id == MouseEvent.MOUSE_PRESSED) { +// src = grab.mousePressed(src, where); +// } else if (id == MouseEvent.MOUSE_RELEASED) { +// src = grab.mouseReleased(src, where); +// } else if (src == null) { +// src = grab.getOwner(); +// } +// +// PopupBox wasActive = activePopup; +// +// if (src != null) { +// mouseEvent(src, id, where, event); +// return src.isMenu() || src.contains(where); +// } +// +// if (wasActive != null && activePopup == null) { +// return wasActive.isMenu(); +// } +// +// if ((id == MouseEvent.MOUSE_PRESSED) +// || (id == MouseEvent.MOUSE_RELEASED)) { +// boolean isMenu = activePopup.isMenu(); +// deactivateAll(); +// return !isMenu; +// } +// return true; +// } +// +// if (activePopup == null) { +// return false; +// } +// +// if ((id >= KeyEvent.KEY_FIRST) && (id <= KeyEvent.KEY_LAST)) { +// boolean isMenu = activePopup.isMenu(); +// activePopup.dispatchKeyEvent(id, event.getVKey(), event +// .getTime(), event.getInputModifiers()); +// +// return isMenu; +// } +// +// return false; +// } +// +// /** +// * Remember the pop-up as active and grab the mouse on it +// * @param popup - the pop-up box to activate +// */ +// void activate(final PopupBox popup) { +// if (activePopup == null) { +// +// activePopup = popup; +// mouseGrabManager.startGrab(popup.getOwner(), new Runnable() { +// public void run() { +// deactivate(popup); +// } +// }); +// } +// } +// +// /** +// * Deactivate the currently active pop-up box +// */ +// void deactivateAll() { +// deactivate(activePopup); +// } +// +// /** +// * Deactivate the pop-up box, end the mouse grab +// */ +// void deactivate(PopupBox popup) { +// grab.reset(); +// +// if (activePopup != null && activePopup == popup) { +// activePopup = null; +// mouseGrabManager.endGrab(); +// popup.hide(); +// underCursor = null; +// } +// } +// +// /** +// * Check that the pop-up box is currently active +// * @param popup - the pop-up box to check +// * @return - true if active +// */ +// boolean isActive(PopupBox popup) { +// return (popup == activePopup) && (popup != null); +// } +// } + +} \ No newline at end of file diff --git a/app/src/main/java/java/awt/Event.java b/app/src/main/java/java/awt/Event.java new file mode 100644 index 000000000..226a61fff --- /dev/null +++ b/app/src/main/java/java/awt/Event.java @@ -0,0 +1,596 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Dmitry A. Durnev + * @version $Revision$ + */ + +package java.awt; + +import java.io.Serializable; + +/** + * The Event class is obsolete and has been replaced by AWTEvent class. + * + * @since Android 1.0 + */ +public class Event implements Serializable { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = 5488922509400504703L; + + /** + * The Constant SHIFT_MASK indicates that the Shift key is down when the + * event occurred. + */ + public static final int SHIFT_MASK = 1; + + /** + * The Constant CTRL_MASK indicates that the Control key is down when the + * event occurred. + */ + public static final int CTRL_MASK = 2; + + /** + * The Constant META_MASK indicates that the Meta key is down when t he + * event occurred (or the right mouse button). + */ + public static final int META_MASK = 4; + + /** + * The Constant ALT_MASK indicates that the Alt key is down when the event + * occurred (or the middle mouse button). + */ + public static final int ALT_MASK = 8; + + /** + * The Constant HOME indicates Home key. + */ + public static final int HOME = 1000; + + /** + * The Constant END indicates End key. + */ + public static final int END = 1001; + + /** + * The Constant PGUP indicates Page Up key. + */ + public static final int PGUP = 1002; + + /** + * The Constant PGDN indicates Page Down key. + */ + public static final int PGDN = 1003; + + /** + * The Constant UP indicates Up key. + */ + public static final int UP = 1004; + + /** + * The Constant DOWN indicates Down key. + */ + public static final int DOWN = 1005; + + /** + * The Constant LEFT indicates Left key. + */ + public static final int LEFT = 1006; + + /** + * The Constant RIGHT indicates Right key. + */ + public static final int RIGHT = 1007; + + /** + * The Constant F1 indicates F1 key. + */ + public static final int F1 = 1008; + + /** + * The Constant F2 indicates F2 key. + */ + public static final int F2 = 1009; + + /** + * The Constant F3 indicates F3 key. + */ + public static final int F3 = 1010; + + /** + * The Constant F4 indicates F4 key. + */ + public static final int F4 = 1011; + + /** + * The Constant F5 indicates F5 key. + */ + public static final int F5 = 1012; + + /** + * The Constant F6 indicates F6 key. + */ + public static final int F6 = 1013; + + /** + * The Constant F7 indicates F7 key. + */ + public static final int F7 = 1014; + + /** + * The Constant F8 indicates F8 key. + */ + public static final int F8 = 1015; + + /** + * The Constant F9 indicates F9 key. + */ + public static final int F9 = 1016; + + /** + * The Constant F10 indicates F10 key. + */ + public static final int F10 = 1017; + + /** + * The Constant F11 indicates F11 key. + */ + public static final int F11 = 1018; + + /** + * The Constant F12 indicates F12 key. + */ + public static final int F12 = 1019; + + /** + * The Constant PRINT_SCREEN indicates Print Screen key. + */ + public static final int PRINT_SCREEN = 1020; + + /** + * The Constant SCROLL_LOCK indicates Scroll Lock key. + */ + public static final int SCROLL_LOCK = 1021; + + /** + * The Constant CAPS_LOCK indicates Caps Lock key. + */ + public static final int CAPS_LOCK = 1022; + + /** + * The Constant NUM_LOCK indicates Num Lock key. + */ + public static final int NUM_LOCK = 1023; + + /** + * The Constant PAUSE indicates Pause key. + */ + public static final int PAUSE = 1024; + + /** + * The Constant INSERT indicates Insert key. + */ + public static final int INSERT = 1025; + + /** + * The Constant ENTER indicates Enter key. + */ + public static final int ENTER = 10; + + /** + * The Constant BACK_SPACE indicates Back Space key. + */ + public static final int BACK_SPACE = 8; + + /** + * The Constant TAB indicates TAb key. + */ + public static final int TAB = 9; + + /** + * The Constant ESCAPE indicates Escape key. + */ + public static final int ESCAPE = 27; + + /** + * The Constant DELETE indicates Delete key. + */ + public static final int DELETE = 127; + + /** + * The Constant WINDOW_DESTROY indicates an event when the user has asked + * the window manager to kill the window. + */ + public static final int WINDOW_DESTROY = 201; + + /** + * The Constant WINDOW_EXPOSE indicates an event when the user has asked the + * window manager to expose the window. + */ + public static final int WINDOW_EXPOSE = 202; + + /** + * The Constant WINDOW_ICONIFY indicates an event when the user has asked + * the window manager to iconify the window. + */ + public static final int WINDOW_ICONIFY = 203; + + /** + * The Constant WINDOW_DEICONIFY indicates an event when the user has asked + * the window manager to deiconify the window. + */ + public static final int WINDOW_DEICONIFY = 204; + + /** + * The Constant WINDOW_MOVED indicates an event when the user has asked the + * window manager to move the window. + */ + public static final int WINDOW_MOVED = 205; + + /** + * The Constant KEY_PRESS indicates an event when the user presses a normal + * key. + */ + public static final int KEY_PRESS = 401; + + /** + * The Constant KEY_RELEASE indicates an event when the user releases a + * normal key. + */ + public static final int KEY_RELEASE = 402; + + /** + * The Constant KEY_ACTION indicates an event when the user pressed a + * non-ASCII action key. + */ + public static final int KEY_ACTION = 403; + + /** + * The Constant KEY_ACTION_RELEASE indicates an event when the user released + * a non-ASCII action key. + */ + public static final int KEY_ACTION_RELEASE = 404; + + /** + * The Constant MOUSE_DOWN indicates an event when the user has pressed the + * mouse button. + */ + public static final int MOUSE_DOWN = 501; + + /** + * The Constant MOUSE_UP indicates an event when the user has released the + * mouse button. + */ + public static final int MOUSE_UP = 502; + + /** + * The Constant MOUSE_MOVE indicates an event when the user has moved the + * mouse with no button pressed. + */ + public static final int MOUSE_MOVE = 503; + + /** + * The Constant MOUSE_ENTER indicates an event when the mouse has entered a + * component. + */ + public static final int MOUSE_ENTER = 504; + + /** + * The Constant MOUSE_EXIT indicates an event when the mouse has exited a + * component. + */ + public static final int MOUSE_EXIT = 505; + + /** + * The Constant MOUSE_DRAG indicates an event when the user has moved a + * mouse with the pressed button. + */ + public static final int MOUSE_DRAG = 506; + + /** + * The Constant SCROLL_LINE_UP indicates an event when the user has + * activated line-up area of scrollbar. + */ + public static final int SCROLL_LINE_UP = 601; + + /** + * The Constant SCROLL_LINE_DOWN indicates an event when the user has + * activated line-down area of scrollbar. + */ + public static final int SCROLL_LINE_DOWN = 602; + + /** + * The Constant SCROLL_PAGE_UP indicates an event when the user has + * activated page up area of scrollbar. + */ + public static final int SCROLL_PAGE_UP = 603; + + /** + * The Constant SCROLL_PAGE_DOWN indicates an event when the user has + * activated page down area of scrollbar. + */ + public static final int SCROLL_PAGE_DOWN = 604; + + /** + * The Constant SCROLL_ABSOLUTE indicates an event when the user has moved + * the bubble in a scroll bar. + */ + public static final int SCROLL_ABSOLUTE = 605; + + /** + * The Constant SCROLL_BEGIN indicates a scroll begin event. + */ + public static final int SCROLL_BEGIN = 606; + + /** + * The Constant SCROLL_END indicates a scroll end event. + */ + public static final int SCROLL_END = 607; + + /** + * The Constant LIST_SELECT indicates that an item in a list has been + * selected. + */ + public static final int LIST_SELECT = 701; + + /** + * The Constant LIST_DESELECT indicates that an item in a list has been + * unselected. + */ + public static final int LIST_DESELECT = 702; + + /** + * The Constant ACTION_EVENT indicates that the user wants some action to + * occur. + */ + public static final int ACTION_EVENT = 1001; + + /** + * The Constant LOAD_FILE indicates a file loading event. + */ + public static final int LOAD_FILE = 1002; + + /** + * The Constant SAVE_FILE indicates a file saving event. + */ + public static final int SAVE_FILE = 1003; + + /** + * The Constant GOT_FOCUS indicates that a component got the focus. + */ + public static final int GOT_FOCUS = 1004; + + /** + * The Constant LOST_FOCUS indicates that the component lost the focus. + */ + public static final int LOST_FOCUS = 1005; + + /** + * The target is the component with which the event is associated. + */ + public Object target; + + /** + * The when is timestamp when event has occured. + */ + public long when; + + /** + * The id indicates the type of the event. + */ + public int id; + + /** + * The x coordinate of event. + */ + public int x; + + /** + * The y coordinate of event. + */ + public int y; + + /** + * The key code of key event. + */ + public int key; + + /** + * The state of the modifier keys (given by a bitmask). + */ + public int modifiers; + + /** + * The click count indicates the number of consecutive clicks. + */ + public int clickCount; + + /** + * The argument of the event. + */ + public Object arg; + + /** + * The next event. + */ + public Event evt; + + /** + * Instantiates a new event with the specified target component, event type, + * and argument. + * + * @param target + * the target component. + * @param id + * the event type. + * @param arg + * the argument. + */ + public Event(Object target, int id, Object arg) { + this(target, 0l, id, 0, 0, 0, 0, arg); + } + + /** + * Instantiates a new event with the specified target component, time stamp, + * event type, x and y coordinates, keyboard key, state of the modifier + * keys, and an argument set to null. + * + * @param target + * the target component. + * @param when + * the time stamp. + * @param id + * the event type. + * @param x + * the x coordinate. + * @param y + * the y coordinate. + * @param key + * the key. + * @param modifiers + * the modifier keys state. + */ + public Event(Object target, long when, int id, int x, int y, int key, int modifiers) { + this(target, when, id, x, y, key, modifiers, null); + } + + /** + * Instantiates a new event with the specified target component, time stamp, + * event type, x and y coordinates, keyboard key, state of the modifier + * keys, and an argument. + * + * @param target + * the target component. + * @param when + * the time stamp. + * @param id + * the event type. + * @param x + * the x coordinate. + * @param y + * the y coordinate. + * @param key + * the key. + * @param modifiers + * the modifier keys state. + * @param arg + * the specified argument. + */ + public Event(Object target, long when, int id, int x, int y, int key, int modifiers, Object arg) { + this.target = target; + this.when = when; + this.id = id; + this.x = x; + this.y = y; + this.key = key; + this.modifiers = modifiers; + this.arg = arg; + } + + /** + * Returns a string representation of this Event. + * + * @return a string representation of this Event. + */ + @Override + public String toString() { + /* + * The format is based on 1.5 release behavior which can be revealed by + * the following code: Event e = new Event(new Button(), 0l, + * Event.KEY_PRESS, 0, 0, Event.TAB, Event.SHIFT_MASK, "arg"); + * System.out.println(e); + */ + + return getClass().getName() + "[" + paramString() + "]"; //$NON-NLS-1$ //$NON-NLS-2$ + } + + /** + * Returns a string representing the state of this Event. + * + * @return a string representing the state of this Event. + */ + protected String paramString() { + return "id=" + id + ",x=" + x + ",y=" + y + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + (key != 0 ? ",key=" + key + getModifiersString() : "") + //$NON-NLS-1$ //$NON-NLS-2$ + ",target=" + target + //$NON-NLS-1$ + (arg != null ? ",arg=" + arg : ""); //$NON-NLS-1$ //$NON-NLS-2$ + } + + /** + * Gets a string representation of the modifiers. + * + * @return a string representation of the modifiers. + */ + private String getModifiersString() { + String strMod = ""; //$NON-NLS-1$ + if (shiftDown()) { + strMod += ",shift"; //$NON-NLS-1$ + } + if (controlDown()) { + strMod += ",control"; //$NON-NLS-1$ + } + if (metaDown()) { + strMod += ",meta"; //$NON-NLS-1$ + } + return strMod; + } + + /** + * Translates x and y coordinates of his event to the x+dx and x+dy + * coordinates. + * + * @param dx + * the distance by which the event's x coordinate is increased. + * @param dy + * the distance by which the event's y coordinate is increased. + */ + public void translate(int dx, int dy) { + x += dx; + y += dy; + } + + /** + * Checks if Control key is down or not. + * + * @return true, if Control key is down; false otherwise. + */ + public boolean controlDown() { + return (modifiers & CTRL_MASK) != 0; + } + + /** + * Checks if Meta key is down or not. + * + * @return true, if Meta key is down; false otherwise. + */ + public boolean metaDown() { + return (modifiers & META_MASK) != 0; + } + + /** + * Checks if Shift key is down or not. + * + * @return true, if Shift key is down; false otherwise. + */ + public boolean shiftDown() { + return (modifiers & SHIFT_MASK) != 0; + } + +} diff --git a/app/src/main/java/java/awt/EventDispatchThread.java b/app/src/main/java/java/awt/EventDispatchThread.java new file mode 100644 index 000000000..442c8a278 --- /dev/null +++ b/app/src/main/java/java/awt/EventDispatchThread.java @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov, Pavel Dolgov + * @version $Revision$ + */ +package java.awt; + +import org.apache.harmony.awt.wtk.NativeEvent; +import org.apache.harmony.awt.wtk.NativeEventQueue; + +class EventDispatchThread extends Thread { + + private static final class MarkerEvent extends AWTEvent { + MarkerEvent(Object source, int id) { + super(source, id); + } + } + + final Dispatcher dispatcher; + final Toolkit toolkit; + private NativeEventQueue nativeQueue; + + protected volatile boolean shutdownPending = false; + + /** + * Initialise and run the main event loop + */ + @Override + public void run() { + nativeQueue = toolkit.getNativeEventQueue(); + + try { + runModalLoop(null); + } finally { + toolkit.shutdownWatchdog.forceShutdown(); + } + } + + void runModalLoop(ModalContext context) { + long lastPaintTime = System.currentTimeMillis(); + while (!shutdownPending && (context == null || context.isModalLoopRunning())) { + try { + EventQueue eventQueue = toolkit.getSystemEventQueueImpl(); + + NativeEvent ne = nativeQueue.getNextEvent(); + if (ne != null) { + dispatcher.onEvent(ne); + MarkerEvent marker = new MarkerEvent(this, 0); + eventQueue.postEvent(marker); + for (AWTEvent ae = eventQueue.getNextEventNoWait(); + (ae != null) && (ae != marker); + ae = eventQueue.getNextEventNoWait()) { + eventQueue.dispatchEvent(ae); + } + } else { + toolkit.shutdownWatchdog.setNativeQueueEmpty(true); + AWTEvent ae = eventQueue.getNextEventNoWait(); + if (ae != null) { + eventQueue.dispatchEvent(ae); + long curTime = System.currentTimeMillis(); + if (curTime - lastPaintTime > 10) { + toolkit.onQueueEmpty(); + lastPaintTime = System.currentTimeMillis(); + } + } else { + toolkit.shutdownWatchdog.setAwtQueueEmpty(true); + toolkit.onQueueEmpty(); + lastPaintTime = System.currentTimeMillis(); + waitForAnyEvent(); + } + } + } catch (Throwable t) { + // TODO: Exception handler should be implemented + // t.printStackTrace(); + } + } + } + + private void waitForAnyEvent() { + EventQueue eventQueue = toolkit.getSystemEventQueueImpl(); + if (!eventQueue.isEmpty() || !nativeQueue.isEmpty()) { + return; + } + Object eventMonitor = nativeQueue.getEventMonitor(); + synchronized(eventMonitor) { + try { + eventMonitor.wait(); + } catch (InterruptedException e) {} + } + } + + void shutdown() { + shutdownPending = true; + } + + EventDispatchThread(Toolkit toolkit, Dispatcher dispatcher ) { + this.toolkit = toolkit; + this.dispatcher = dispatcher; + setName("AWT-EventDispatchThread"); //$NON-NLS-1$ + setDaemon(true); + } + +} diff --git a/app/src/main/java/java/awt/EventQueue.java b/app/src/main/java/java/awt/EventQueue.java new file mode 100644 index 000000000..126a59306 --- /dev/null +++ b/app/src/main/java/java/awt/EventQueue.java @@ -0,0 +1,320 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov, Pavel Dolgov + * @version $Revision$ + */ + +package java.awt; + +import java.awt.event.InvocationEvent; +import java.lang.reflect.InvocationTargetException; +import java.util.EmptyStackException; + +/** + * The EventQueue class manages events. It is a platform-independent class that + * queues events both from the underlying peer classes and from trusted + * application classes. + * + * @since Android 1.0 + */ +public class EventQueue { + + /** + * The core ref. + */ + private final EventQueueCoreAtomicReference coreRef = new EventQueueCoreAtomicReference(); + + /** + * The Class EventQueueCoreAtomicReference. + */ + private static final class EventQueueCoreAtomicReference { + + /** + * The core. + */ + private EventQueueCore core; + + /* synchronized */ + /** + * Gets the. + * + * @return the event queue core. + */ + EventQueueCore get() { + return core; + } + + /* synchronized */ + /** + * Sets the. + * + * @param newCore + * the new core. + */ + void set(EventQueueCore newCore) { + core = newCore; + } + } + + /** + * Returns true if the calling thread is the current AWT EventQueue's + * dispatch thread. + * + * @return true, if the calling thread is the current AWT EventQueue's + * dispatch thread; false otherwise. + */ + public static boolean isDispatchThread() { + return Thread.currentThread() instanceof EventDispatchThread; + } + + /** + * Posts an InvocationEvent which executes the run() method on a Runnable + * when dispatched by the AWT event dispatcher thread. + * + * @param runnable + * the Runnable whose run method should be executed synchronously + * on the EventQueue. + */ + public static void invokeLater(Runnable runnable) { + Toolkit toolkit = Toolkit.getDefaultToolkit(); + InvocationEvent event = new InvocationEvent(toolkit, runnable); + toolkit.getSystemEventQueueImpl().postEvent(event); + } + + /** + * Posts an InvocationEvent which executes the run() method on a Runnable + * when dispatched by the AWT event dispatcher thread and the notifyAll + * method is called on it immediately after run returns. + * + * @param runnable + * the Runnable whose run method should be executed synchronously + * on the EventQueue. + * @throws InterruptedException + * if another thread has interrupted this thread. + * @throws InvocationTargetException + * if an error occurred while running the runnable. + */ + public static void invokeAndWait(Runnable runnable) throws InterruptedException, + InvocationTargetException { + + if (isDispatchThread()) { + throw new Error(); + } + + final Toolkit toolkit = Toolkit.getDefaultToolkit(); + final Object notifier = new Object(); // $NON-LOCK-1$ + InvocationEvent event = new InvocationEvent(toolkit, runnable, notifier, true); + + synchronized (notifier) { + toolkit.getSystemEventQueueImpl().postEvent(event); + notifier.wait(); + } + + Exception exception = event.getException(); + + if (exception != null) { + throw new InvocationTargetException(exception); + } + } + + /** + * Gets the system event queue. + * + * @return the system event queue. + */ + private static EventQueue getSystemEventQueue() { + Thread th = Thread.currentThread(); + if (th instanceof EventDispatchThread) { + return ((EventDispatchThread)th).toolkit.getSystemEventQueueImpl(); + } + return null; + } + + /** + * Gets the most recent event's timestamp. This event was dispatched from + * the EventQueue associated with the calling thread. + * + * @return the timestamp of the last Event to be dispatched, or + * System.currentTimeMillis() if this method is invoked from a + * thread other than an event-dispatching thread. + */ + public static long getMostRecentEventTime() { + EventQueue eq = getSystemEventQueue(); + return (eq != null) ? eq.getMostRecentEventTimeImpl() : System.currentTimeMillis(); + } + + /** + * Gets the most recent event time impl. + * + * @return the most recent event time impl. + */ + private long getMostRecentEventTimeImpl() { + return getCore().getMostRecentEventTime(); + } + + /** + * Returns the the currently dispatched event by the EventQueue associated + * with the calling thread. + * + * @return the currently dispatched event or null if this method is invoked + * from a thread other than an event-dispatching thread. + */ + public static AWTEvent getCurrentEvent() { + EventQueue eq = getSystemEventQueue(); + return (eq != null) ? eq.getCurrentEventImpl() : null; + } + + /** + * Gets the current event impl. + * + * @return the current event impl. + */ + private AWTEvent getCurrentEventImpl() { + return getCore().getCurrentEvent(); + } + + /** + * Instantiates a new event queue. + */ + public EventQueue() { + setCore(new EventQueueCore(this)); + } + + /** + * Instantiates a new event queue. + * + * @param t + * the t. + */ + EventQueue(Toolkit t) { + setCore(new EventQueueCore(this, t)); + } + + /** + * Posts a event to the EventQueue. + * + * @param event + * AWTEvent. + */ + public void postEvent(AWTEvent event) { + event.isPosted = true; + getCore().postEvent(event); + } + + /** + * Returns an event from the EventQueue and removes it from this queue. + * + * @return the next AWTEvent. + * @throws InterruptedException + * is thrown if another thread interrupts this thread. + */ + public AWTEvent getNextEvent() throws InterruptedException { + return getCore().getNextEvent(); + } + + /** + * Gets the next event no wait. + * + * @return the next event no wait. + */ + AWTEvent getNextEventNoWait() { + return getCore().getNextEventNoWait(); + } + + /** + * Returns the first event of the EventQueue (without removing it from the + * queue). + * + * @return the the first AWT event of the EventQueue. + */ + public AWTEvent peekEvent() { + return getCore().peekEvent(); + } + + /** + * Returns the first event of the EventQueue with the specified ID (without + * removing it from the queue). + * + * @param id + * the type ID of event. + * @return the first event of the EventQueue with the specified ID. + */ + public AWTEvent peekEvent(int id) { + return getCore().peekEvent(id); + } + + /** + * Replaces the existing EventQueue with the specified EventQueue. Any + * pending events are transferred to the new EventQueue. + * + * @param newEventQueue + * the new event queue. + */ + public void push(EventQueue newEventQueue) { + getCore().push(newEventQueue); + } + + /** + * Stops dispatching events using this EventQueue. Any pending events are + * transferred to the previous EventQueue. + * + * @throws EmptyStackException + * is thrown if no previous push was made on this EventQueue. + */ + protected void pop() throws EmptyStackException { + getCore().pop(); + } + + /** + * Dispatches the specified event. + * + * @param event + * the AWTEvent. + */ + protected void dispatchEvent(AWTEvent event) { + getCore().dispatchEventImpl(event); + } + + /** + * Checks if the queue is empty. + * + * @return true, if is empty. + */ + boolean isEmpty() { + return getCore().isEmpty(); + } + + /** + * Gets the core. + * + * @return the core. + */ + EventQueueCore getCore() { + return coreRef.get(); + } + + /** + * Sets the core. + * + * @param newCore + * the new core. + */ + void setCore(EventQueueCore newCore) { + coreRef.set((newCore != null) ? newCore : new EventQueueCore(this)); + } +} diff --git a/app/src/main/java/java/awt/EventQueueCore.java b/app/src/main/java/java/awt/EventQueueCore.java new file mode 100644 index 000000000..ffc7c46f4 --- /dev/null +++ b/app/src/main/java/java/awt/EventQueueCore.java @@ -0,0 +1,253 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt; + +import java.awt.event.ActionEvent; +import java.awt.event.InputEvent; +import java.awt.event.InputMethodEvent; +import java.awt.event.InvocationEvent; +import java.awt.event.MouseEvent; +import java.util.LinkedList; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The events storage for EventQueue + */ +final class EventQueueCore { + + private final LinkedList queueStack = new LinkedList(); + private final LinkedList events = new LinkedList(); + + private Toolkit toolkit; + private EventQueue activeQueue; + private Thread dispatchThread; + + AWTEvent currentEvent; + long mostRecentEventTime = System.currentTimeMillis(); + + EventQueueCore(EventQueue eq) { + synchronized (this) { + queueStack.addLast(eq); + activeQueue = eq; + } + } + + EventQueueCore(EventQueue eq, Toolkit t) { + synchronized (this) { + queueStack.addLast(eq); + activeQueue = eq; + setToolkit(t); + } + } + + synchronized long getMostRecentEventTime() { + return mostRecentEventTime; + } + + synchronized AWTEvent getCurrentEvent() { + return currentEvent; + } + + synchronized boolean isSystemEventQueue() { + return toolkit != null; + } + + private void setToolkit(Toolkit t) { + toolkit = t; + if (toolkit != null) { + toolkit.setSystemEventQueueCore(this); + dispatchThread = toolkit.dispatchThread; + } + } + + synchronized void postEvent(AWTEvent event) { + //???AWT + /* + events.addLast(event); + if ((toolkit == null) && (dispatchThread == null)) { + dispatchThread = new EventQueueThread(this); + dispatchThread.start(); + } + // TODO: add event coalescing + if (toolkit != null) { + toolkit.shutdownWatchdog.setAwtQueueEmpty(false); + if (!GraphicsEnvironment.getLocalGraphicsEnvironment().isHeadlessInstance()) { + notifyEventMonitor(toolkit); + } + } + notifyAll(); + */ + } + + void notifyEventMonitor(Toolkit t) { + Object em = t.getNativeEventQueue().getEventMonitor(); + synchronized (em) { + em.notifyAll(); + } + } + + synchronized AWTEvent getNextEvent() throws InterruptedException { + while (events.isEmpty()) { + wait(); + } + AWTEvent event = events.removeFirst(); + // TODO: add event coalescing + return event; + } + + synchronized AWTEvent peekEvent() { + return events.isEmpty() ? null : events.getFirst(); + } + + synchronized AWTEvent peekEvent(int id) { + for (AWTEvent event : events) { + if (event.getID() == id) { + return event; + } + } + return null; + } + + synchronized void dispatchEvent(AWTEvent event) { + updateCurrentEventAndTime(event); + try { + activeQueue.dispatchEvent(event); + } finally { + currentEvent = null; + } + } + + void dispatchEventImpl(AWTEvent event) { + if (event instanceof ActiveEvent) { + updateCurrentEventAndTime(event); + try { + ((ActiveEvent) event).dispatch(); + } finally { + currentEvent = null; + } + return; + } + + Object src = event.getSource(); + + if (src instanceof Component) { + if (preprocessComponentEvent(event)) { + ((Component) src).dispatchEvent(event); + } + } else { + if (toolkit != null) { + toolkit.dispatchAWTEvent(event); + } + if (src instanceof MenuComponent) { + ((MenuComponent) src).dispatchEvent(event); + } + } + } + + private final boolean preprocessComponentEvent(AWTEvent event) { + if (event instanceof MouseEvent) { + return preprocessMouseEvent((MouseEvent)event); + } + return true; + } + + private final boolean preprocessMouseEvent(MouseEvent event) { + //???AWT + /* + if (toolkit != null && toolkit.mouseEventPreprocessor != null) { + toolkit.lockAWT(); + try { + return toolkit.mouseEventPreprocessor.preprocess(event); + } finally { + toolkit.unlockAWT(); + } + } + return true; + */ + return true; + } + + private void updateCurrentEventAndTime(AWTEvent event) { + currentEvent = event; + long when = 0; + if (event instanceof ActionEvent) { + when = ((ActionEvent) event).getWhen(); + } else if (event instanceof InputEvent) { + when = ((InputEvent) event).getWhen(); + } else if (event instanceof InputMethodEvent) { + when = ((InputMethodEvent) event).getWhen(); + } else if (event instanceof InvocationEvent) { + when = ((InvocationEvent) event).getWhen(); + } + if (when != 0) { + mostRecentEventTime = when; + } + } + + synchronized void push(EventQueue newEventQueue) { + // TODO: handle incorrect situations + if (queueStack.isEmpty()) { + // awt.6B=Queue stack is empty + throw new IllegalStateException(Messages.getString("awt.6B")); //$NON-NLS-1$ + } + + queueStack.addLast(newEventQueue); + activeQueue = newEventQueue; + activeQueue.setCore(this); + } + + synchronized void pop() { + EventQueue removed = queueStack.removeLast(); + if (removed != activeQueue) { + // awt.6C=Event queue stack is broken + throw new IllegalStateException(Messages.getString("awt.6C")); //$NON-NLS-1$ + } + activeQueue = queueStack.getLast(); + removed.setCore(null); + } + + synchronized AWTEvent getNextEventNoWait() { + try { + return events.isEmpty() ? null : activeQueue.getNextEvent(); + } catch (InterruptedException e) { + return null; + } + } + + synchronized boolean isEmpty() { + return (currentEvent == null) && events.isEmpty(); + } + + synchronized boolean isEmpty(long timeout) { + if (!isEmpty()) { + return false; + } + try { + wait(timeout); + } catch (InterruptedException e) {} + return isEmpty(); + } + + synchronized EventQueue getActiveEventQueue() { + return activeQueue; + } +} diff --git a/app/src/main/java/java/awt/Font.java b/app/src/main/java/java/awt/Font.java index 61a9ca951..b86afeec3 100644 --- a/app/src/main/java/java/awt/Font.java +++ b/app/src/main/java/java/awt/Font.java @@ -1,19 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package java.awt; -import java.awt.font.*; -import java.awt.geom.*; -import java.io.*; -import java.util.*; -import java.text.AttributedCharacterIterator.Attribute; +import com.android.internal.awt.AndroidGraphics2D; -public class Font implements Serializable - { +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.font.LineMetrics; +import java.awt.font.TextAttribute; +import java.awt.font.TransformAttribute; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.io.File; +import java.io.FileInputStream; +import java.io.BufferedInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; +import java.text.CharacterIterator; +import java.text.AttributedCharacterIterator.Attribute; +import java.util.Hashtable; +import java.util.Locale; +import java.util.Map; +import java.util.StringTokenizer; + +import org.apache.harmony.awt.gl.font.AndroidGlyphVector; +import org.apache.harmony.awt.gl.font.CommonGlyphVector; +import org.apache.harmony.awt.gl.font.FontPeerImpl; +import org.apache.harmony.awt.gl.font.FontMetricsImpl; +import org.apache.harmony.awt.gl.font.LineMetricsImpl; +import org.apache.harmony.awt.internal.nls.Messages; +import org.apache.harmony.luni.util.NotImplementedException; +import org.apache.harmony.misc.HashCode; + +/** + * The Font class represents fonts for rendering text. This class allow to map + * characters to glyphs. + *

+ * A glyph is a shape used to render a character or a sequence of characters. + * For example one character of Latin writing system represented by one glyph, + * but in complex writing system such as South and South-East Asian there is + * more complicated correspondence between characters and glyphs. + *

+ * The Font object is identified by two types of names. The logical font name is + * the name that is used to construct the font. The font name is the name of a + * particular font face (for example, Arial Bold). The family name is the font's + * family name that specifies the typographic design across several faces (for + * example, Arial). In all the Font is identified by three attributes: the + * family name, the style (such as bold or italic), and the size. + * + * @since Android 1.0 + */ +public class Font implements Serializable { /** * The Constant serialVersionUID. */ private static final long serialVersionUID = -4206021311591459213L; + // Identity Transform attribute + /** + * The Constant IDENTITY_TRANSFORM. + */ + private static final TransformAttribute IDENTITY_TRANSFORM = new TransformAttribute( + new AffineTransform()); + /** * The Constant PLAIN indicates font's plain style. */ @@ -113,6 +180,12 @@ public class Font implements Serializable */ private Hashtable fRequestedAttributes; + // font peer object corresponding to this Font + /** + * The font peer. + */ + private transient FontPeerImpl fontPeer; + // number of glyphs in this Font /** * The num glyphs. @@ -124,7 +197,40 @@ public class Font implements Serializable * The missing glyph code. */ private transient int missingGlyphCode = -1; - /** + + /** + * Writes object to ObjectOutputStream. + * + * @param out + * ObjectOutputStream. + * @throws IOException + * Signals that an I/O exception has occurred. + */ + private void writeObject(java.io.ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + } + + /** + * Reads object from ObjectInputStream object and set native platform + * dependent fields to default values. + * + * @param in + * ObjectInputStream object. + * @throws IOException + * Signals that an I/O exception has occurred. + * @throws ClassNotFoundException + * the class not found exception. + */ + private void readObject(java.io.ObjectInputStream in) throws IOException, + ClassNotFoundException { + in.defaultReadObject(); + + numGlyphs = -1; + missingGlyphCode = -1; + + } + + /** * Instantiates a new Font with the specified attributes. The Font will be * created with default attributes if the attribute's parameter is null. * @@ -159,7 +265,7 @@ public class Font implements Serializable currAttr = attributes.get(TextAttribute.WEIGHT); if ((currAttr != null) - && (((Float)currAttr).floatValue() >= (TextAttribute.WEIGHT_BOLD).floatValue())) { + && (((Float)currAttr).floatValue() >= (TextAttribute.WEIGHT_BOLD).floatValue())) { this.style |= Font.BOLD; } @@ -170,19 +276,17 @@ public class Font implements Serializable currAttr = attributes.get(TextAttribute.TRANSFORM); if (currAttr != null) { - /* if (currAttr instanceof TransformAttribute) { this.transformed = !((TransformAttribute)currAttr).getTransform().isIdentity(); - } else - */ - if (currAttr instanceof AffineTransform) { + } else if (currAttr instanceof AffineTransform) { this.transformed = !((AffineTransform)currAttr).isIdentity(); } } } else { fRequestedAttributes = new Hashtable(5); - + fRequestedAttributes.put(TextAttribute.TRANSFORM, IDENTITY_TRANSFORM); + this.transformed = false; fRequestedAttributes.put(TextAttribute.FAMILY, name); @@ -222,7 +326,7 @@ public class Font implements Serializable fRequestedAttributes = new Hashtable(5); - // fRequestedAttributes.put(TextAttribute.TRANSFORM, IDENTITY_TRANSFORM); + fRequestedAttributes.put(TextAttribute.TRANSFORM, IDENTITY_TRANSFORM); this.transformed = false; @@ -240,5 +344,1198 @@ public class Font implements Serializable fRequestedAttributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_REGULAR); } } - + + /** + * Returns true if this Font has a glyph for the specified character. + * + * @param c + * the character. + * @return true if this Font has a glyph for the specified character, false + * otherwise. + */ + public boolean canDisplay(char c) { + FontPeerImpl peer = (FontPeerImpl)this.getPeer(); + return peer.canDisplay(c); + } + + /** + * Returns true if the Font can display the characters of the the specified + * text from the specified start position to the specified limit position. + * + * @param text + * the text. + * @param start + * the start offset (in the character array). + * @param limit + * the limit offset (in the character array). + * @return the a character's position in the text that this Font can not + * display, or -1 if this Font can display all characters in this + * text. + */ + public int canDisplayUpTo(char[] text, int start, int limit) { + int st = start; + int result; + while ((st < limit) && canDisplay(text[st])) { + st++; + } + + if (st == limit) { + result = -1; + } else { + result = st; + } + + return result; + } + + /** + * Returns true if the Font can display the characters of the the specified + * CharacterIterator from the specified start position and the specified + * limit position. + * + * @param iter + * the CharacterIterator. + * @param start + * the start offset. + * @param limit + * the limit offset. + * @return the a character's position in the CharacterIterator that this + * Font can not display, or -1 if this Font can display all + * characters in this text. + */ + public int canDisplayUpTo(CharacterIterator iter, int start, int limit) { + int st = start; + char c = iter.setIndex(start); + int result; + + while ((st < limit) && (canDisplay(c))) { + st++; + c = iter.next(); + } + if (st == limit) { + result = -1; + } else { + result = st; + } + + return result; + } + + /** + * Returns true if this Font can display a specified String. + * + * @param str + * the String. + * @return the a character's position in the String that this Font can not + * display, or -1 if this Font can display all characters in this + * text. + */ + public int canDisplayUpTo(String str) { + char[] chars = str.toCharArray(); + return canDisplayUpTo(chars, 0, chars.length); + } + + /** + * Creates a GlyphVector of associating characters to glyphs based on the + * Unicode map of this Font. + * + * @param frc + * the FontRenderContext. + * @param chars + * the characters array. + * @return the GlyphVector of associating characters to glyphs based on the + * Unicode map of this Font. + */ + public GlyphVector createGlyphVector(FontRenderContext frc, char[] chars) { + return new AndroidGlyphVector(chars, frc, this, 0); + } + + /** + * Creates a GlyphVector of associating characters contained in the + * specified CharacterIterator to glyphs based on the Unicode map of this + * Font. + * + * @param frc + * the FontRenderContext. + * @param iter + * the CharacterIterator. + * @return the GlyphVector of associating characters contained in the + * specified CharacterIterator to glyphs based on the Unicode map of + * this Font. + */ + public GlyphVector createGlyphVector(FontRenderContext frc, CharacterIterator iter) { + throw new RuntimeException("Not implemented!"); //$NON-NLS-1$ + } + + /** + * Creates a GlyphVector of associating characters to glyphs based on the + * Unicode map of this Font. + * + * @param frc + * the FontRenderContext. + * @param glyphCodes + * the specified integer array of glyph codes. + * @return the GlyphVector of associating characters to glyphs based on the + * Unicode map of this Font. + * @throws NotImplementedException + * if this method is not implemented by a subclass. + */ + public GlyphVector createGlyphVector(FontRenderContext frc, int[] glyphCodes) + throws org.apache.harmony.luni.util.NotImplementedException { + throw new RuntimeException("Not implemented!"); //$NON-NLS-1$ + } + + /** + * Creates a GlyphVector of associating characters to glyphs based on the + * Unicode map of this Font. + * + * @param frc + * the FontRenderContext. + * @param str + * the specified String. + * @return the GlyphVector of associating characters to glyphs based on the + * Unicode map of this Font. + */ + public GlyphVector createGlyphVector(FontRenderContext frc, String str) { + return new AndroidGlyphVector(str.toCharArray(), frc, this, 0); + + } + + /** + * Returns the font style constant value corresponding to one of the font + * style names ("BOLD", "ITALIC", "BOLDITALIC"). This method returns + * Font.PLAIN if the argument is not one of the predefined style names. + * + * @param fontStyleName + * font style name. + * @return font style constant value corresponding to the font style name + * specified. + */ + private static int getFontStyle(String fontStyleName) { + int result = Font.PLAIN; + + if (fontStyleName.toUpperCase().equals("BOLDITALIC")) { //$NON-NLS-1$ + result = Font.BOLD | Font.ITALIC; + } else if (fontStyleName.toUpperCase().equals("BOLD")) { //$NON-NLS-1$ + result = Font.BOLD; + } else if (fontStyleName.toUpperCase().equals("ITALIC")) { //$NON-NLS-1$ + result = Font.ITALIC; + } + + return result; + } + + /** + * Decodes the specified string which described the Font. The string should + * have the following format: fontname-style-pointsize. The style can be + * PLAIN, BOLD, BOLDITALIC, or ITALIC. + * + * @param str + * the string which describes the font. + * @return the Font from the specified string. + */ + public static Font decode(String str) { + // XXX: Documentation doesn't describe all cases, e.g. fonts face names + // with + // symbols that are suggested as delimiters in the documentation. + // In this decode implementation only ***-***-*** format is used with + // '-' + // as the delimiter to avoid unexpected parse results of font face names + // with spaces. + + if (str == null) { + return DEFAULT_FONT; + } + + StringTokenizer strTokens; + String delim = "-"; //$NON-NLS-1$ + String substr; + + int fontSize = DEFAULT_FONT.size; + int fontStyle = DEFAULT_FONT.style; + String fontName = DEFAULT_FONT.name; + + strTokens = new StringTokenizer(str.trim(), delim); + + // Font Name + if (strTokens.hasMoreTokens()) { + fontName = strTokens.nextToken(); // first token is the font name + } + + // Font Style or Size (if the style is undefined) + if (strTokens.hasMoreTokens()) { + substr = strTokens.nextToken(); + + try { + // if second token is the font size + fontSize = Integer.parseInt(substr); + } catch (NumberFormatException e) { + // then second token is the font style + fontStyle = getFontStyle(substr); + } + + } + + // Font Size + if (strTokens.hasMoreTokens()) { + try { + fontSize = Integer.parseInt(strTokens.nextToken()); + } catch (NumberFormatException e) { + } + } + + return new Font(fontName, fontStyle, fontSize); + } + + /** + * Performs the specified affine transform to the Font and returns a new + * Font. + * + * @param trans + * the AffineTransform. + * @return the Font object. + * @throws IllegalArgumentException + * if affine transform parameter is null. + */ + @SuppressWarnings("unchecked") + public Font deriveFont(AffineTransform trans) { + + if (trans == null) { + // awt.94=transform can not be null + throw new IllegalArgumentException(Messages.getString("awt.94")); //$NON-NLS-1$ + } + + Hashtable derivefRequestedAttributes = (Hashtable)fRequestedAttributes + .clone(); + + derivefRequestedAttributes.put(TextAttribute.TRANSFORM, new TransformAttribute(trans)); + + return new Font(derivefRequestedAttributes); + + } + + /** + * Returns a new Font that is a copy of the current Font modified so that + * the size is the specified size. + * + * @param size + * the size of font. + * @return the Font object. + */ + @SuppressWarnings("unchecked") + public Font deriveFont(float size) { + Hashtable derivefRequestedAttributes = (Hashtable)fRequestedAttributes + .clone(); + derivefRequestedAttributes.put(TextAttribute.SIZE, new Float(size)); + return new Font(derivefRequestedAttributes); + } + + /** + * Returns a new Font that is a copy of the current Font modified so that + * the style is the specified style. + * + * @param style + * the style of font. + * @return the Font object. + */ + @SuppressWarnings("unchecked") + public Font deriveFont(int style) { + Hashtable derivefRequestedAttributes = (Hashtable)fRequestedAttributes + .clone(); + + if ((style & Font.BOLD) != 0) { + derivefRequestedAttributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); + } else if (derivefRequestedAttributes.get(TextAttribute.WEIGHT) != null) { + derivefRequestedAttributes.remove(TextAttribute.WEIGHT); + } + + if ((style & Font.ITALIC) != 0) { + derivefRequestedAttributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE); + } else if (derivefRequestedAttributes.get(TextAttribute.POSTURE) != null) { + derivefRequestedAttributes.remove(TextAttribute.POSTURE); + } + + return new Font(derivefRequestedAttributes); + } + + /** + * Returns a new Font that is a copy of the current Font modified to match + * the specified style and with the specified affine transform applied to + * its glyphs. + * + * @param style + * the style of font. + * @param trans + * the AffineTransform. + * @return the Font object. + */ + @SuppressWarnings("unchecked") + public Font deriveFont(int style, AffineTransform trans) { + + if (trans == null) { + // awt.94=transform can not be null + throw new IllegalArgumentException(Messages.getString("awt.94")); //$NON-NLS-1$ + } + Hashtable derivefRequestedAttributes = (Hashtable)fRequestedAttributes + .clone(); + + if ((style & BOLD) != 0) { + derivefRequestedAttributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); + } else if (derivefRequestedAttributes.get(TextAttribute.WEIGHT) != null) { + derivefRequestedAttributes.remove(TextAttribute.WEIGHT); + } + + if ((style & ITALIC) != 0) { + derivefRequestedAttributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE); + } else if (derivefRequestedAttributes.get(TextAttribute.POSTURE) != null) { + derivefRequestedAttributes.remove(TextAttribute.POSTURE); + } + derivefRequestedAttributes.put(TextAttribute.TRANSFORM, new TransformAttribute(trans)); + + return new Font(derivefRequestedAttributes); + } + + /** + * Returns a new Font that is a copy of the current Font modified so that + * the size and style are the specified size and style. + * + * @param style + * the style of font. + * @param size + * the size of font. + * @return the Font object. + */ + @SuppressWarnings("unchecked") + public Font deriveFont(int style, float size) { + Hashtable derivefRequestedAttributes = (Hashtable)fRequestedAttributes + .clone(); + + if ((style & BOLD) != 0) { + derivefRequestedAttributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); + } else if (derivefRequestedAttributes.get(TextAttribute.WEIGHT) != null) { + derivefRequestedAttributes.remove(TextAttribute.WEIGHT); + } + + if ((style & ITALIC) != 0) { + derivefRequestedAttributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE); + } else if (derivefRequestedAttributes.get(TextAttribute.POSTURE) != null) { + derivefRequestedAttributes.remove(TextAttribute.POSTURE); + } + + derivefRequestedAttributes.put(TextAttribute.SIZE, new Float(size)); + return new Font(derivefRequestedAttributes); + + } + + /** + * Returns a new Font object with a new set of font attributes. + * + * @param attributes + * the map of attributes. + * @return the Font. + */ + @SuppressWarnings("unchecked") + public Font deriveFont(Map attributes) { + Attribute[] avalAttributes = this.getAvailableAttributes(); + + Hashtable derivefRequestedAttributes = (Hashtable)fRequestedAttributes + .clone(); + Object currAttribute; + for (Attribute element : avalAttributes) { + currAttribute = attributes.get(element); + if (currAttribute != null) { + derivefRequestedAttributes.put(element, currAttribute); + } + } + return new Font(derivefRequestedAttributes); + } + + /** + * Compares the specified Object with the current Font. + * + * @param obj + * the Object to be compared. + * @return true, if the specified Object is an instance of Font with the + * same family, size, and style as this Font, false otherwise. + */ + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + + if (obj != null) { + try { + Font font = (Font)obj; + + return ((this.style == font.style) && (this.size == font.size) + && this.name.equals(font.name) && (this.pointSize == font.pointSize) && (this + .getTransform()).equals(font.getTransform())); + } catch (ClassCastException e) { + } + } + + return false; + } + + /** + * Gets the map of font's attributes. + * + * @return the map of font's attributes. + */ + @SuppressWarnings("unchecked") + public Map getAttributes() { + return (Map)fRequestedAttributes.clone(); + } + + /** + * Gets the keys of all available attributes. + * + * @return the keys array of all available attributes. + */ + public Attribute[] getAvailableAttributes() { + Attribute[] attrs = { + TextAttribute.FAMILY, TextAttribute.POSTURE, TextAttribute.SIZE, + TextAttribute.TRANSFORM, TextAttribute.WEIGHT, TextAttribute.SUPERSCRIPT, + TextAttribute.WIDTH + }; + return attrs; + } + + /** + * Gets the baseline for this character. + * + * @param c + * the character. + * @return the baseline for this character. + */ + public byte getBaselineFor(char c) { + // TODO: implement using TT BASE table data + return 0; + } + + /** + * Gets the family name of the Font. + * + * @return the family name of the Font. + */ + public String getFamily() { + if (fRequestedAttributes != null) { + fRequestedAttributes.get(TextAttribute.FAMILY); + } + return null; + } + + /** + * Returns the family name of this Font associated with the specified + * locale. + * + * @param l + * the locale. + * @return the family name of this Font associated with the specified + * locale. + */ + public String getFamily(Locale l) { + if (l == null) { + // awt.01='{0}' parameter is null + throw new NullPointerException(Messages.getString("awt.01", "Locale")); //$NON-NLS-1$ //$NON-NLS-2$ + } + return getFamily(); + } + + /** + * Gets a Font with the specified attribute set. + * + * @param attributes + * the attributes to be assigned to the new Font. + * @return the Font. + */ + public static Font getFont(Map attributes) { + Font fnt = (Font)attributes.get(TextAttribute.FONT); + if (fnt != null) { + return fnt; + } + return new Font(attributes); + } + + /** + * Gets a Font object from the system properties list with the specified + * name or returns the specified Font if there is no such property. + * + * @param sp + * the specified property name. + * @param f + * the Font. + * @return the Font object from the system properties list with the + * specified name or the specified Font if there is no such + * property. + */ + public static Font getFont(String sp, Font f) { + String pr = System.getProperty(sp); + if (pr == null) { + return f; + } + return decode(pr); + } + + /** + * Gets a Font object from the system properties list with the specified + * name. + * + * @param sp + * the system property name. + * @return the Font, or null if there is no such property with the specified + * name. + */ + public static Font getFont(String sp) { + return getFont(sp, null); + } + + /** + * Gets the font name. + * + * @return the font name. + */ + public String getFontName() { + if (fRequestedAttributes != null) { + fRequestedAttributes.get(TextAttribute.FAMILY); + } + return null; + } + + /** + * Returns the font name associated with the specified locale. + * + * @param l + * the locale. + * @return the font name associated with the specified locale. + */ + public String getFontName(Locale l) { + return getFamily(); + } + + /** + * Returns a LineMetrics object created with the specified parameters. + * + * @param chars + * the chars array. + * @param start + * the start offset. + * @param end + * the end offset. + * @param frc + * the FontRenderContext. + * @return the LineMetrics for the specified parameters. + */ + public LineMetrics getLineMetrics(char[] chars, int start, int end, FontRenderContext frc) { + if (frc == null) { + // awt.00=FontRenderContext is null + throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$ + } + + // FontMetrics fm = AndroidGraphics2D.getInstance().getFontMetrics(); + FontMetrics fm = new FontMetricsImpl(this); + float[] fmet = { + fm.getAscent(), fm.getDescent(), fm.getLeading() + }; + return new LineMetricsImpl(chars.length, fmet, null); + } + + /** + * Returns a LineMetrics object created with the specified parameters. + * + * @param iter + * the CharacterIterator. + * @param start + * the start offset. + * @param end + * the end offset. + * @param frc + * the FontRenderContext. + * @return the LineMetrics for the specified parameters. + */ + public LineMetrics getLineMetrics(CharacterIterator iter, int start, int end, + FontRenderContext frc) { + + if (frc == null) { + // awt.00=FontRenderContext is null + throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$ + } + + String resultString; + int iterCount; + + iterCount = end - start; + if (iterCount < 0) { + resultString = ""; //$NON-NLS-1$ + } else { + char[] chars = new char[iterCount]; + int i = 0; + for (char c = iter.setIndex(start); c != CharacterIterator.DONE && (i < iterCount); c = iter + .next()) { + chars[i] = c; + i++; + } + resultString = new String(chars); + } + return this.getLineMetrics(resultString, frc); + } + + /** + * Returns a LineMetrics object created with the specified parameters. + * + * @param str + * the String. + * @param frc + * the FontRenderContext. + * @return the LineMetrics for the specified parameters. + */ + public LineMetrics getLineMetrics(String str, FontRenderContext frc) { + // FontMetrics fm = AndroidGraphics2D.getInstance().getFontMetrics(); + FontMetrics fm = new FontMetricsImpl(this); + float[] fmet = { + fm.getAscent(), fm.getDescent(), fm.getLeading() + }; + // Log.i("FONT FMET", fmet.toString()); + return new LineMetricsImpl(str.length(), fmet, null); + + } + + /** + * Returns a LineMetrics object created with the specified parameters. + * + * @param str + * the String. + * @param start + * the start offset. + * @param end + * the end offset. + * @param frc + * the FontRenderContext. + * @return the LineMetrics for the specified parameters. + */ + public LineMetrics getLineMetrics(String str, int start, int end, FontRenderContext frc) { + return this.getLineMetrics(str.substring(start, end), frc); + } + + /** + * Gets the logical bounds of the specified String in the specified + * FontRenderContext. The logical bounds contains the origin, ascent, + * advance, and height. + * + * @param ci + * the specified CharacterIterator. + * @param start + * the start offset. + * @param end + * the end offset. + * @param frc + * the FontRenderContext. + * @return a Rectangle2D object. + */ + public Rectangle2D getStringBounds(CharacterIterator ci, int start, int end, + FontRenderContext frc) { + int first = ci.getBeginIndex(); + int finish = ci.getEndIndex(); + char[] chars; + + if (start < first) { + // awt.95=Wrong start index: {0} + throw new IndexOutOfBoundsException(Messages.getString("awt.95", start)); //$NON-NLS-1$ + } + if (end > finish) { + // awt.96=Wrong finish index: {0} + throw new IndexOutOfBoundsException(Messages.getString("awt.96", end)); //$NON-NLS-1$ + } + if (start > end) { + // awt.97=Wrong range length: {0} + throw new IndexOutOfBoundsException(Messages.getString("awt.97", //$NON-NLS-1$ + (end - start))); + } + + if (frc == null) { + throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$ + } + + chars = new char[end - start]; + + ci.setIndex(start); + for (int i = 0; i < chars.length; i++) { + chars[i] = ci.current(); + ci.next(); + } + + return this.getStringBounds(chars, 0, chars.length, frc); + + } + + /** + * Gets the logical bounds of the specified String in the specified + * FontRenderContext. The logical bounds contains the origin, ascent, + * advance, and height. + * + * @param str + * the specified String. + * @param frc + * the FontRenderContext. + * @return a Rectangle2D object. + */ + public Rectangle2D getStringBounds(String str, FontRenderContext frc) { + char[] chars = str.toCharArray(); + return this.getStringBounds(chars, 0, chars.length, frc); + + } + + /** + * Gets the logical bounds of the specified String in the specified + * FontRenderContext. The logical bounds contains the origin, ascent, + * advance, and height. + * + * @param str + * the specified String. + * @param start + * the start offset. + * @param end + * the end offset. + * @param frc + * the FontRenderContext. + * @return a Rectangle2D object. + */ + public Rectangle2D getStringBounds(String str, int start, int end, FontRenderContext frc) { + + return this.getStringBounds((str.substring(start, end)), frc); + } + + /** + * Gets the logical bounds of the specified String in the specified + * FontRenderContext. The logical bounds contains the origin, ascent, + * advance, and height. + * + * @param chars + * the specified character array. + * @param start + * the start offset. + * @param end + * the end offset. + * @param frc + * the FontRenderContext. + * @return a Rectangle2D object. + */ + public Rectangle2D getStringBounds(char[] chars, int start, int end, FontRenderContext frc) { + if (start < 0) { + // awt.95=Wrong start index: {0} + throw new IndexOutOfBoundsException(Messages.getString("awt.95", start)); //$NON-NLS-1$ + } + if (end > chars.length) { + // awt.96=Wrong finish index: {0} + throw new IndexOutOfBoundsException(Messages.getString("awt.96", end)); //$NON-NLS-1$ + } + if (start > end) { + // awt.97=Wrong range length: {0} + throw new IndexOutOfBoundsException(Messages.getString("awt.97", //$NON-NLS-1$ + (end - start))); + } + + if (frc == null) { + throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$ + } + + FontPeerImpl peer = (FontPeerImpl)this.getPeer(); + + final int TRANSFORM_MASK = AffineTransform.TYPE_GENERAL_ROTATION + | AffineTransform.TYPE_GENERAL_TRANSFORM; + Rectangle2D bounds; + + AffineTransform transform = getTransform(); + + // XXX: for transforms where an angle between basis vectors is not 90 + // degrees Rectanlge2D class doesn't fit as Logical bounds. + if ((transform.getType() & TRANSFORM_MASK) == 0) { + int width = 0; + for (int i = start; i < end; i++) { + width += peer.charWidth(chars[i]); + } + // LineMetrics nlm = peer.getLineMetrics(); + + LineMetrics nlm = getLineMetrics(chars, start, end, frc); + + bounds = transform.createTransformedShape( + new Rectangle2D.Float(0, -nlm.getAscent(), width, nlm.getHeight())) + .getBounds2D(); + } else { + int len = end - start; + char[] subChars = new char[len]; + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(chars, start, subChars, 0, len); + bounds = createGlyphVector(frc, subChars).getLogicalBounds(); + } + return bounds; + } + + /** + * Gets the character's maximum bounds as defined in the specified + * FontRenderContext. + * + * @param frc + * the FontRenderContext. + * @return the character's maximum bounds. + */ + public Rectangle2D getMaxCharBounds(FontRenderContext frc) { + if (frc == null) { + // awt.00=FontRenderContext is null + throw new NullPointerException(Messages.getString("awt.00")); //$NON-NLS-1$ + } + + FontPeerImpl peer = (FontPeerImpl)this.getPeer(); + + Rectangle2D bounds = peer.getMaxCharBounds(frc); + AffineTransform transform = getTransform(); + // !! Documentation doesn't describe meaning of max char bounds + // for the fonts that have rotate transforms. For all transforms + // returned bounds are the bounds of transformed maxCharBounds + // Rectangle2D that corresponds to the font with identity transform. + // TODO: resolve this issue to return correct bounds + bounds = transform.createTransformedShape(bounds).getBounds2D(); + + return bounds; + } + + /** + * Returns a new GlyphVector object performing full layout of the text. + * + * @param frc + * the FontRenderContext. + * @param chars + * the character array to be layout. + * @param start + * the start offset of the text to use for the GlyphVector. + * @param count + * the count of characters to use for the GlyphVector. + * @param flags + * the flag indicating text direction: LAYOUT_RIGHT_TO_LEFT, + * LAYOUT_LEFT_TO_RIGHT. + * @return the GlyphVector. + */ + public GlyphVector layoutGlyphVector(FontRenderContext frc, char[] chars, int start, int count, + int flags) { + // TODO: implement method for bidirectional text. + // At the moment only LTR and RTL texts supported. + if (start < 0) { + // awt.95=Wrong start index: {0} + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.95", //$NON-NLS-1$ + start)); + } + + if (count < 0) { + // awt.98=Wrong count value, can not be negative: {0} + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.98", //$NON-NLS-1$ + count)); + } + + if (start + count > chars.length) { + // awt.99=Wrong [start + count] is out of range: {0} + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.99", //$NON-NLS-1$ + (start + count))); + } + + char[] out = new char[count]; + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(chars, start, out, 0, count); + + return new CommonGlyphVector(out, frc, this, flags); + } + + /** + * Returns the String representation of this Font. + * + * @return the String representation of this Font. + */ + @Override + public String toString() { + String stl = "plain"; //$NON-NLS-1$ + String result; + + if (this.isBold() && this.isItalic()) { + stl = "bolditalic"; //$NON-NLS-1$ + } + if (this.isBold() && !this.isItalic()) { + stl = "bold"; //$NON-NLS-1$ + } + + if (!this.isBold() && this.isItalic()) { + stl = "italic"; //$NON-NLS-1$ + } + + result = this.getClass().getName() + "[family=" + this.getFamily() + //$NON-NLS-1$ + ",name=" + this.name + //$NON-NLS-1$ + ",style=" + stl + //$NON-NLS-1$ + ",size=" + this.size + "]"; //$NON-NLS-1$ //$NON-NLS-2$ + return result; + } + + /** + * Gets the postscript name of this Font. + * + * @return the postscript name of this Font. + */ + public String getPSName() { + FontPeerImpl peer = (FontPeerImpl)this.getPeer(); + return peer.getPSName(); + } + + /** + * Gets the logical name of this Font. + * + * @return the logical name of this Font. + */ + public String getName() { + return (this.name); + } + + /** + * Gets the peer of this Font. + * + * @return the peer of this Font. + * @deprecated Font rendering is platform independent now. + */ + @Deprecated + public java.awt.peer.FontPeer getPeer() { + if (fontPeer == null) { + fontPeer = (FontPeerImpl)Toolkit.getDefaultToolkit().getGraphicsFactory().getFontPeer( + this); + } + return fontPeer; + + } + + /** + * Gets the transform acting on this Font (from the Font's attributes). + * + * @return the transformation of this Font. + */ + public AffineTransform getTransform() { + Object transform = fRequestedAttributes.get(TextAttribute.TRANSFORM); + + if (transform != null) { + if (transform instanceof TransformAttribute) { + return ((TransformAttribute)transform).getTransform(); + } + if (transform instanceof AffineTransform) { + return new AffineTransform((AffineTransform)transform); + } + } else { + transform = new AffineTransform(); + } + return (AffineTransform)transform; + + } + + /** + * Checks if this font is transformed or not. + * + * @return true, if this font is transformed, false otherwise. + */ + public boolean isTransformed() { + return this.transformed; + } + + /** + * Checks if this font has plain style or not. + * + * @return true, if this font has plain style, false otherwise. + */ + public boolean isPlain() { + return (this.style == PLAIN); + } + + /** + * Checks if this font has italic style or not. + * + * @return true, if this font has italic style, false otherwise. + */ + public boolean isItalic() { + return (this.style & ITALIC) != 0; + } + + /** + * Checks if this font has bold style or not. + * + * @return true, if this font has bold style, false otherwise. + */ + public boolean isBold() { + return (this.style & BOLD) != 0; + } + + /** + * Returns true if this Font has uniform line metrics. + * + * @return true if this Font has uniform line metrics, false otherwise. + */ + public boolean hasUniformLineMetrics() { + FontPeerImpl peer = (FontPeerImpl)this.getPeer(); + return peer.hasUniformLineMetrics(); + } + + /** + * Returns hash code of this Font object. + * + * @return the hash code of this Font object. + */ + @Override + public int hashCode() { + HashCode hash = new HashCode(); + + hash.append(this.name); + hash.append(this.style); + hash.append(this.size); + + return hash.hashCode(); + } + + /** + * Gets the style of this Font. + * + * @return the style of this Font. + */ + public int getStyle() { + return this.style; + } + + /** + * Gets the size of this Font. + * + * @return the size of this Font. + */ + public int getSize() { + return this.size; + } + + /** + * Gets the number of glyphs for this Font. + * + * @return the number of glyphs for this Font. + */ + public int getNumGlyphs() { + if (numGlyphs == -1) { + FontPeerImpl peer = (FontPeerImpl)this.getPeer(); + this.numGlyphs = peer.getNumGlyphs(); + } + return this.numGlyphs; + } + + /** + * Gets the glyphCode which is used as default glyph when this Font does not + * have a glyph for a specified Unicode. + * + * @return the missing glyph code. + */ + public int getMissingGlyphCode() { + if (missingGlyphCode == -1) { + FontPeerImpl peer = (FontPeerImpl)this.getPeer(); + this.missingGlyphCode = peer.getMissingGlyphCode(); + } + return this.missingGlyphCode; + } + + /** + * Gets the float value of font's size. + * + * @return the float value of font's size. + */ + public float getSize2D() { + return this.pointSize; + } + + /** + * Gets the italic angle of this Font. + * + * @return the italic angle of this Font. + */ + public float getItalicAngle() { + FontPeerImpl peer = (FontPeerImpl)this.getPeer(); + return peer.getItalicAngle(); + } + + /** + * Creates the font with the specified font format and font file. + * + * @param fontFormat + * the font format. + * @param fontFile + * the file object represented the input data for the font. + * @return the Font. + * @throws FontFormatException + * is thrown if fontFile does not contain the required font + * tables for the specified format. + * @throws IOException + * signals that an I/O exception has occurred. + */ + public static Font createFont(int fontFormat, File fontFile) throws FontFormatException, + IOException { + // ???AWT not supported + InputStream is = new FileInputStream(fontFile); + try { + return createFont(fontFormat, is); + } finally { + is.close(); + } + } + + /** + * Creates the font with the specified font format and input stream. + * + * @param fontFormat + * the font format. + * @param fontStream + * the input stream represented input data for the font. + * @return the Font. + * @throws FontFormatException + * is thrown if fontFile does not contain the required font + * tables for the specified format. + * @throws IOException + * signals that an I/O exception has occurred. + */ + public static Font createFont(int fontFormat, InputStream fontStream) + throws FontFormatException, IOException { + + // ???AWT not supported + + BufferedInputStream buffStream; + int bRead = 0; + int size = 8192; + // memory page size, for the faster reading + byte buf[] = new byte[size]; + + if (fontFormat != TRUETYPE_FONT) { // awt.9A=Unsupported font format + throw new IllegalArgumentException(Messages.getString("awt.9A")); //$NON-NLS-1$ + } + + /* Get font file in system-specific directory */ + + File fontFile = Toolkit.getDefaultToolkit().getGraphicsFactory().getFontManager() + .getTempFontFile(); + + // BEGIN android-modified + buffStream = new BufferedInputStream(fontStream, 8192); + // END android-modified + FileOutputStream fOutStream = new FileOutputStream(fontFile); + + bRead = buffStream.read(buf, 0, size); + + while (bRead != -1) { + fOutStream.write(buf, 0, bRead); + bRead = buffStream.read(buf, 0, size); + } + + buffStream.close(); + fOutStream.close(); + + Font font = null; + + font = Toolkit.getDefaultToolkit().getGraphicsFactory().embedFont( + fontFile.getAbsolutePath()); + if (font == null) { // awt.9B=Can't create font - bad font data + throw new FontFormatException(Messages.getString("awt.9B")); //$NON-NLS-1$ + } + return font; + } + } diff --git a/app/src/main/java/java/awt/FontMetrics.java b/app/src/main/java/java/awt/FontMetrics.java new file mode 100644 index 000000000..90826265a --- /dev/null +++ b/app/src/main/java/java/awt/FontMetrics.java @@ -0,0 +1,466 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ + +package java.awt; + +import java.awt.font.FontRenderContext; +import java.awt.font.LineMetrics; +import java.awt.geom.Rectangle2D; +import java.io.Serializable; +import java.text.CharacterIterator; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The FontMetrics class contains information about the rendering of a + * particular font on a particular screen. + *

+ * Each character in the Font has three values that help define where to place + * it: an ascent, a descent, and an advance. The ascent is the distance the + * character extends above the baseline. The descent is the distance the + * character extends below the baseline. The advance width defines the position + * at which the next character should be placed. + *

+ * An array of characters or a string has an ascent, a descent, and an advance + * width too. The ascent or descent of the array is specified by the maximum + * ascent or descent of the characters in the array. The advance width is the + * sum of the advance widths of each of the characters in the character array. + *

+ * + * @since Android 1.0 + */ +public abstract class FontMetrics implements Serializable { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = 1681126225205050147L; + + /** + * The font from which the FontMetrics is created. + */ + protected Font font; + + /** + * Instantiates a new font metrics from the specified Font. + * + * @param fnt + * the Font. + */ + protected FontMetrics(Font fnt) { + this.font = fnt; + } + + /** + * Returns the String representation of this FontMetrics. + * + * @return the string. + */ + @Override + public String toString() { + return this.getClass().getName() + "[font=" + this.getFont() + //$NON-NLS-1$ + "ascent=" + this.getAscent() + //$NON-NLS-1$ + ", descent=" + this.getDescent() + //$NON-NLS-1$ + ", height=" + this.getHeight() + "]"; //$NON-NLS-1$ //$NON-NLS-2$ + } + + /** + * Gets the font associated with this FontMetrics. + * + * @return the font associated with this FontMetrics. + */ + public Font getFont() { + return font; + } + + /** + * Gets the height of the text line in this Font. + * + * @return the height of the text line in this Font. + */ + public int getHeight() { + return this.getAscent() + this.getDescent() + this.getLeading(); + } + + /** + * Gets the font ascent of the Font associated with this FontMetrics. The + * font ascent is the distance from the font's baseline to the top of most + * alphanumeric characters. + * + * @return the ascent of the Font associated with this FontMetrics. + */ + public int getAscent() { + return 0; + } + + /** + * Gets the font descent of the Font associated with this FontMetrics. The + * font descent is the distance from the font's baseline to the bottom of + * most alphanumeric characters with descenders. + * + * @return the descent of the Font associated with this FontMetrics. + */ + public int getDescent() { + return 0; + } + + /** + * Gets the leading of the Font associated with this FontMetrics. + * + * @return the leading of the Font associated with this FontMetrics. + */ + public int getLeading() { + return 0; + } + + /** + * Gets the LineMetrics object for the specified CharacterIterator in the + * specified Graphics. + * + * @param ci + * the CharacterIterator. + * @param beginIndex + * the offset. + * @param limit + * the number of characters to be used. + * @param context + * the Graphics. + * @return the LineMetrics object for the specified CharacterIterator in the + * specified Graphics. + */ + public LineMetrics getLineMetrics(CharacterIterator ci, int beginIndex, int limit, + Graphics context) { + return font.getLineMetrics(ci, beginIndex, limit, this.getFRCFromGraphics(context)); + } + + /** + * Gets the LineMetrics object for the specified String in the specified + * Graphics. + * + * @param str + * the String. + * @param context + * the Graphics. + * @return the LineMetrics object for the specified String in the specified + * Graphics. + */ + public LineMetrics getLineMetrics(String str, Graphics context) { + return font.getLineMetrics(str, this.getFRCFromGraphics(context)); + } + + /** + * Gets the LineMetrics object for the specified character array in the + * specified Graphics. + * + * @param chars + * the character array. + * @param beginIndex + * the offset of array. + * @param limit + * the number of characters to be used. + * @param context + * the Graphics. + * @return the LineMetrics object for the specified character array in the + * specified Graphics. + */ + public LineMetrics getLineMetrics(char[] chars, int beginIndex, int limit, Graphics context) { + return font.getLineMetrics(chars, beginIndex, limit, this.getFRCFromGraphics(context)); + } + + /** + * Gets the LineMetrics object for the specified String in the specified + * Graphics. + * + * @param str + * the String. + * @param beginIndex + * the offset. + * @param limit + * the number of characters to be used. + * @param context + * the Graphics. + * @return the LineMetrics object for the specified String in the specified + * Graphics. + */ + public LineMetrics getLineMetrics(String str, int beginIndex, int limit, Graphics context) { + return font.getLineMetrics(str, beginIndex, limit, this.getFRCFromGraphics(context)); + } + + /** + * Returns the character's maximum bounds in the specified Graphics context. + * + * @param context + * the Graphics context. + * @return the character's maximum bounds in the specified Graphics context. + */ + public Rectangle2D getMaxCharBounds(Graphics context) { + return this.font.getMaxCharBounds(this.getFRCFromGraphics(context)); + } + + /** + * Gets the bounds of the specified CharacterIterator in the specified + * Graphics context. + * + * @param ci + * the CharacterIterator. + * @param beginIndex + * the begin offset of the array. + * @param limit + * the number of characters. + * @param context + * the Graphics. + * @return the bounds of the specified CharacterIterator in the specified + * Graphics context. + */ + public Rectangle2D getStringBounds(CharacterIterator ci, int beginIndex, int limit, + Graphics context) { + return font.getStringBounds(ci, beginIndex, limit, this.getFRCFromGraphics(context)); + } + + /** + * Gets the bounds of the specified String in the specified Graphics + * context. + * + * @param str + * the String. + * @param beginIndex + * the begin offset of the array. + * @param limit + * the number of characters. + * @param context + * the Graphics. + * @return the bounds of the specified String in the specified Graphics + * context. + */ + public Rectangle2D getStringBounds(String str, int beginIndex, int limit, Graphics context) { + return font.getStringBounds(str, beginIndex, limit, this.getFRCFromGraphics(context)); + } + + /** + * Gets the bounds of the specified characters array in the specified + * Graphics context. + * + * @param chars + * the characters array. + * @param beginIndex + * the begin offset of the array. + * @param limit + * the number of characters. + * @param context + * the Graphics. + * @return the bounds of the specified characters array in the specified + * Graphics context. + */ + public Rectangle2D getStringBounds(char[] chars, int beginIndex, int limit, Graphics context) { + return font.getStringBounds(chars, beginIndex, limit, this.getFRCFromGraphics(context)); + } + + /** + * Gets the bounds of the specified String in the specified Graphics + * context. + * + * @param str + * the String. + * @param context + * the Graphics. + * @return the bounds of the specified String in the specified Graphics + * context. + */ + public Rectangle2D getStringBounds(String str, Graphics context) { + return font.getStringBounds(str, this.getFRCFromGraphics(context)); + } + + /** + * Checks if the Font has uniform line metrics or not. The Font can contain + * characters of other fonts for covering character set. In this case the + * Font isn't uniform. + * + * @return true, if the Font has uniform line metrics, false otherwise. + */ + public boolean hasUniformLineMetrics() { + return this.font.hasUniformLineMetrics(); + } + + /** + * Returns the distance from the leftmost point to the rightmost point on + * the string's baseline showing the specified array of bytes in this Font. + * + * @param data + * the array of bytes to be measured. + * @param off + * the start offset. + * @param len + * the number of bytes to be measured. + * @return the advance width of the array. + */ + public int bytesWidth(byte[] data, int off, int len) { + int width = 0; + if ((off >= data.length) || (off < 0)) { + // awt.13B=offset off is out of range + throw new IllegalArgumentException(Messages.getString("awt.13B")); //$NON-NLS-1$ + } + + if ((off + len > data.length)) { + // awt.13C=number of elemets len is out of range + throw new IllegalArgumentException(Messages.getString("awt.13C")); //$NON-NLS-1$ + } + + for (int i = off; i < off + len; i++) { + width += charWidth(data[i]); + } + + return width; + } + + /** + * Returns the distance from the leftmost point to the rightmost point on + * the string's baseline showing the specified array of characters in this + * Font. + * + * @param data + * the array of characters to be measured. + * @param off + * the start offset. + * @param len + * the number of bytes to be measured. + * @return the advance width of the array. + */ + public int charsWidth(char[] data, int off, int len) { + int width = 0; + if ((off >= data.length) || (off < 0)) { + // awt.13B=offset off is out of range + throw new IllegalArgumentException(Messages.getString("awt.13B")); //$NON-NLS-1$ + } + + if ((off + len > data.length)) { + // awt.13C=number of elemets len is out of range + throw new IllegalArgumentException(Messages.getString("awt.13C")); //$NON-NLS-1$ + } + + for (int i = off; i < off + len; i++) { + width += charWidth(data[i]); + } + + return width; + } + + /** + * Returns the distance from the leftmost point to the rightmost point of + * the specified character in this Font. + * + * @param ch + * the specified Unicode point code of character to be measured. + * @return the advance width of the character. + */ + public int charWidth(int ch) { + return 0; + } + + /** + * Returns the distance from the leftmost point to the rightmost point of + * the specified character in this Font. + * + * @param ch + * the specified character to be measured. + * @return the advance width of the character. + */ + public int charWidth(char ch) { + return 0; + } + + /** + * Gets the maximum advance width of character in this Font. + * + * @return the maximum advance width of character in this Font. + */ + public int getMaxAdvance() { + return 0; + } + + /** + * Gets the maximum font ascent of the Font associated with this + * FontMetrics. + * + * @return the maximum font ascent of the Font associated with this + * FontMetrics. + */ + public int getMaxAscent() { + return 0; + } + + /** + * Gets the maximum font descent of character in this Font. + * + * @return the maximum font descent of character in this Font. + * @deprecated Replaced by getMaxDescent() method. + */ + @Deprecated + public int getMaxDecent() { + return 0; + } + + /** + * Gets the maximum font descent of character in this Font. + * + * @return the maximum font descent of character in this Font. + */ + public int getMaxDescent() { + return 0; + } + + /** + * Gets the advance widths of the characters in the Font. + * + * @return the advance widths of the characters in the Font. + */ + public int[] getWidths() { + return null; + } + + /** + * Returns the advance width for the specified String in this Font. + * + * @param str + * String to be measured. + * @return the the advance width for the specified String in this Font. + */ + public int stringWidth(String str) { + return 0; + } + + /** + * Returns a FontRenderContext instance of the Graphics context specified. + * + * @param context + * the specified Graphics context. + * @return a FontRenderContext of the specified Graphics context. + */ + private FontRenderContext getFRCFromGraphics(Graphics context) { + FontRenderContext frc; + if (context instanceof Graphics2D) { + frc = ((Graphics2D)context).getFontRenderContext(); + } else { + frc = new FontRenderContext(null, false, false); + } + + return frc; + } +} diff --git a/app/src/main/java/java/awt/GradientPaint.java b/app/src/main/java/java/awt/GradientPaint.java new file mode 100644 index 000000000..3b32ef530 --- /dev/null +++ b/app/src/main/java/java/awt/GradientPaint.java @@ -0,0 +1,255 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.awt; + +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.image.ColorModel; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The GradientPaint class defines a way to fill a Shape with a linear color + * gradient pattern. + *

+ * The GradientPaint's fill pattern is determined by two points and two colors, + * plus the cyclic mode option. Each of the two points is painted with its + * corresponding color, and on the line segment connecting the two points, the + * color is proportionally changed between the two colors. For points on the + * same line which are not between the two specified points (outside of the + * connecting segment) their color is determined by the cyclic mode option. If + * the mode is cyclic, then the rest of the line repeats the color pattern of + * the connecting segment, cycling back and forth between the two colors. If + * not, the mode is acyclic which means that all points on the line outside the + * connecting line segment are given the same color as the closest of the two + * specified points. + *

+ * The color of points that are not on the line connecting the two specified + * points are given by perpendicular projection: by taking the set of lines + * perpendicular to the connecting line and for each one, the whole line is + * colored with the same color. + * + * @since Android 1.0 + */ +public class GradientPaint implements Paint { + + /** + * The start point color. + */ + Color color1; + + /** + * The end color point. + */ + Color color2; + + /** + * The location of the start point. + */ + Point2D point1; + + /** + * The location of the end point. + */ + Point2D point2; + + /** + * The indicator of cycle filling. If TRUE filling repeated outside points + * stripe, if FALSE solid color filling outside. + */ + boolean cyclic; + + /** + * Instantiates a new GradientPaint with cyclic or acyclic mode. + * + * @param point1 + * the first specified point. + * @param color1 + * the Color of the first specified point. + * @param point2 + * the second specified point. + * @param color2 + * the Color of the second specified point. + * @param cyclic + * the cyclic mode - true if the gradient pattern should cycle + * repeatedly between the two colors; false otherwise. + */ + public GradientPaint(Point2D point1, Color color1, Point2D point2, Color color2, boolean cyclic) { + if (point1 == null || point2 == null) { + // awt.6D=Point is null + throw new NullPointerException(Messages.getString("awt.6D")); //$NON-NLS-1$ + } + if (color1 == null || color2 == null) { + // awt.6E=Color is null + throw new NullPointerException(Messages.getString("awt.6E")); //$NON-NLS-1$ + } + + this.point1 = point1; + this.point2 = point2; + this.color1 = color1; + this.color2 = color2; + this.cyclic = cyclic; + } + + /** + * Instantiates a new GradientPaint with cyclic or acyclic mode; points are + * specified by coordinates. + * + * @param x1 + * the X coordinate of the first point. + * @param y1 + * the Y coordinate of the first point. + * @param color1 + * the color of the first point. + * @param x2 + * the X coordinate of the second point. + * @param y2 + * the Y coordinate of the second point. + * @param color2 + * the color of the second point. + * @param cyclic + * the cyclic mode - true if the gradient pattern should cycle + * repeatedly between the two colors; false otherwise. + */ + public GradientPaint(float x1, float y1, Color color1, float x2, float y2, Color color2, + boolean cyclic) { + this(new Point2D.Float(x1, y1), color1, new Point2D.Float(x2, y2), color2, cyclic); + } + + /** + * Instantiates a new acyclic GradientPaint; points are specified by + * coordinates. + * + * @param x1 + * the X coordinate of the first point. + * @param y1 + * the Y coordinate of the first point. + * @param color1 + * the color of the first point. + * @param x2 + * the X coordinate of the second point. + * @param y2 + * the Y coordinate of the second point. + * @param color2 + * the color of the second point. + */ + public GradientPaint(float x1, float y1, Color color1, float x2, float y2, Color color2) { + this(x1, y1, color1, x2, y2, color2, false); + } + + /** + * Instantiates a new acyclic GradientPaint. + * + * @param point1 + * the first specified point. + * @param color1 + * the Color of the first specified point. + * @param point2 + * the second specified point. + * @param color2 + * the Color of the second specified point. + */ + public GradientPaint(Point2D point1, Color color1, Point2D point2, Color color2) { + this(point1, color1, point2, color2, false); + } + + /** + * Creates PaintContext for a color pattern generating. + * + * @param cm + * the ColorModel of the Paint data. + * @param deviceBounds + * the bounding Rectangle of graphics primitives being rendered + * in the device space. + * @param userBounds + * the bounding Rectangle of graphics primitives being rendered + * in the user space. + * @param t + * the AffineTransform from user space into device space. + * @param hints + * the RrenderingHints object. + * @return the PaintContext for color pattern generating. + * @see java.awt.Paint#createContext(java.awt.image.ColorModel, + * java.awt.Rectangle, java.awt.geom.Rectangle2D, + * java.awt.geom.AffineTransform, java.awt.RenderingHints) + */ + public PaintContext createContext(ColorModel cm, Rectangle deviceBounds, + Rectangle2D userBounds, AffineTransform t, RenderingHints hints) { + return new GradientPaintContext(cm, t, point1, color1, point2, color2, cyclic); + } + + /** + * Gets the color of the first point. + * + * @return the color of the first point. + */ + public Color getColor1() { + return color1; + } + + /** + * Gets the color of the second point. + * + * @return the color of the second point. + */ + public Color getColor2() { + return color2; + } + + /** + * Gets the first point. + * + * @return the Point object - the first point. + */ + public Point2D getPoint1() { + return point1; + } + + /** + * Gets the second point. + * + * @return the Point object - the second point. + */ + public Point2D getPoint2() { + return point2; + } + + /** + * Gets the transparency mode for the GradientPaint. + * + * @return the transparency mode for the GradientPaint. + * @see java.awt.Transparency#getTransparency() + */ + public int getTransparency() { + int a1 = color1.getAlpha(); + int a2 = color2.getAlpha(); + return (a1 == 0xFF && a2 == 0xFF) ? OPAQUE : TRANSLUCENT; + } + + /** + * Returns the GradientPaint mode: true for cyclic mode, false for acyclic + * mode. + * + * @return true if the gradient cycles repeatedly between the two colors; + * false otherwise. + */ + public boolean isCyclic() { + return cyclic; + } +} diff --git a/app/src/main/java/java/awt/GradientPaintContext.java b/app/src/main/java/java/awt/GradientPaintContext.java new file mode 100644 index 000000000..74575f56d --- /dev/null +++ b/app/src/main/java/java/awt/GradientPaintContext.java @@ -0,0 +1,204 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Denis M. Kishenko + * @version $Revision$ + */ +package java.awt; + +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.awt.image.ColorModel; +import java.awt.image.DataBufferInt; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; + +class GradientPaintContext implements PaintContext { + + /** + * The size of noncyclic part of color lookup table + */ + static int LOOKUP_SIZE = 256; + + /** + * The index mask to lookup color in the table + */ + static int LOOKUP_MASK = 0x1FF; + + /** + * The min value equivalent to zero. If absolute value less then ZERO it considered as zero. + */ + static double ZERO = 1E-10; + + /** + * The ColorModel user defined for PaintContext + */ + ColorModel cm; + + /** + * The indicator of cycle filling. + */ + boolean cyclic; + + /** + * The integer color value of the start point + */ + int c1; + + /** + * The integer color value of the end point + */ + int c2; + + /** + * The lookup gradient color table + */ + int[] table; + + /** + * The tempopary pre-calculated value to evalutae color index + */ + int dx; + + /** + * The tempopary pre-calculated value to evalutae color index + */ + int dy; + + /** + * The tempopary pre-calculated value to evalutae color index + */ + int delta; + + /** + * Constructs a new GradientPaintcontext + * @param cm - not used + * @param t - the fill transformation + * @param point1 - the start fill point + * @param color1 - color of the start point + * @param point2 - the end fill point + * @param color2 - color of the end point + * @param cyclic - the indicator of cycle filling + */ + GradientPaintContext(ColorModel cm, AffineTransform t, Point2D point1, Color color1, Point2D point2, Color color2, boolean cyclic) { + this.cyclic = cyclic; + this.cm = ColorModel.getRGBdefault(); + + c1 = color1.getRGB(); + c2 = color2.getRGB(); + + double px = point2.getX() - point1.getX(); + double py = point2.getY() - point1.getY(); + + Point2D p = t.transform(point1, null); + Point2D bx = new Point2D.Double(px, py); + Point2D by = new Point2D.Double(py, -px); + + t.deltaTransform(bx, bx); + t.deltaTransform(by, by); + + double vec = bx.getX() * by.getY() - bx.getY() * by.getX(); + + if (Math.abs(vec) < ZERO) { + dx = dy = delta = 0; + table = new int[1]; + table[0] = c1; + } else { + double mult = LOOKUP_SIZE * 256 / vec; + dx = (int)(by.getX() * mult); + dy = (int)(by.getY() * mult); + delta = (int)((p.getX() * by.getY() - p.getY() * by.getX()) * mult); + createTable(); + } + } + + /** + * Create color index lookup table. Calculate 256 step trasformation from + * the start point color to the end point color. Colors multiplied by 256 to do integer calculations. + */ + void createTable() { + double ca = (c1 >> 24) & 0xFF; + double cr = (c1 >> 16) & 0xFF; + double cg = (c1 >> 8) & 0xFF; + double cb = c1 & 0xFF; + + double k = 1.0 / LOOKUP_SIZE; + double da = (((c2 >> 24) & 0xFF) - ca) * k; + double dr = (((c2 >> 16) & 0xFF) - cr) * k; + double dg = (((c2 >> 8) & 0xFF) - cg) * k; + double db = ((c2 & 0xFF) - cb) * k; + + table = new int[cyclic ? LOOKUP_SIZE + LOOKUP_SIZE : LOOKUP_SIZE]; + for(int i = 0; i < LOOKUP_SIZE; i++) { + table[i] = + (int)ca << 24 | + (int)cr << 16 | + (int)cg << 8 | + (int)cb; + ca += da; + cr += dr; + cg += dg; + cb += db; + } + if (cyclic) { + for(int i = 0; i < LOOKUP_SIZE; i++) { + table[LOOKUP_SIZE + LOOKUP_SIZE - 1 - i] = table[i]; + } + } + } + + public ColorModel getColorModel() { + return cm; + } + + public void dispose() { + } + + public Raster getRaster(int x, int y, int w, int h) { + WritableRaster rast = cm.createCompatibleWritableRaster(w, h); + + int[] buf = ((DataBufferInt)rast.getDataBuffer()).getData(); + + int c = x * dy - y * dx - delta; + int cx = dy; + int cy = - w * dy - dx; + int k = 0; + + if (cyclic) { + for(int j = 0; j < h; j++) { + for(int i = 0; i < w; i++) { + buf[k++] = table[(c >> 8) & LOOKUP_MASK]; + c += cx; + } + c += cy; + } + } else { + for(int j = 0; j < h; j++) { + for(int i = 0; i < w; i++) { + int index = c >> 8; + buf[k++] = index < 0 ? c1 : index >= LOOKUP_SIZE ? c2 : table[index]; + c += cx; + } + c += cy; + } + } + + return rast; + } + +} + diff --git a/app/src/main/java/java/awt/Graphics.java b/app/src/main/java/java/awt/Graphics.java index 474a50114..2d6e79fca 100644 --- a/app/src/main/java/java/awt/Graphics.java +++ b/app/src/main/java/java/awt/Graphics.java @@ -1,42 +1,924 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey A. Petrenko + * @version $Revision$ + */ + package java.awt; -import java.awt.image.BufferedImage; import java.awt.image.ImageObserver; +import java.text.AttributedCharacterIterator; -import android.graphics.Canvas; -import android.graphics.Paint; +/** + * The abstract Graphics class allows applications to draw on a screen or other + * rendering target. There are several properties which define rendering + * options: origin point, clipping area, color, font.
+ *
+ * The origin point specifies the beginning of the clipping area coordinate + * system. All coordinates used in rendering operations are computed with + * respect to this point. The clipping area defines the boundaries where + * rendering operations can be performed. Rendering operations can't modify + * pixels outside of the clipping area.
+ *
+ * The draw and fill methods allow applications to drawing shapes, text, images + * with specified font and color options in the specified part of the screen. + * + * @since Android 1.0 + */ +public abstract class Graphics { -public class Graphics { - private Paint androidPaint; - private Canvas androidCanvas; - private BufferedImage bufImage; + // Constructors - public Graphics(BufferedImage bufImage) { - this.bufImage = bufImage; - this.androidCanvas = new Canvas(bufImage.getAndroidBitmap()); - this.androidPaint = new Paint(); + /** + * Instantiates a new Graphics. This constructor is default for Graphics and + * can not be called directly. + */ + protected Graphics() { } - public void setColor(Color color) { - androidPaint.setColor(color.hashCode()); + // Public methods + + /** + * Creates a copy of the Graphics object with a new origin and a new + * specified clip area. The new clip area is the rectangle defined by the + * origin point with coordinates X,Y and the given width and height. The + * coordinates of all subsequent rendering operations will be computed with + * respect to the new origin and can be performed only within the range of + * the clipping area dimensions. + * + * @param x + * the X coordinate of the original point. + * @param y + * the Y coordinate of the original point. + * @param width + * the width of clipping area. + * @param height + * the height of clipping area. + * @return the Graphics object with new origin point and clipping area. + */ + public Graphics create(int x, int y, int width, int height) { + Graphics res = create(); + res.translate(x, y); + res.clipRect(0, 0, width, height); + return res; } - public void fillRect(int x, int y, int width, int height) { - this.androidCanvas.drawRect(x, y, x + width, y + height, androidPaint); - } + /** + * Draws the highlighted outline of a rectangle. + * + * @param x + * the X coordinate of the rectangle's top left corner. + * @param y + * the Y coordinate of the rectangle's top left corner. + * @param width + * the width of rectangle. + * @param height + * the height of rectangle. + * @param raised + * a boolean value that determines whether the rectangle is drawn + * as raised or indented. + */ + public void draw3DRect(int x, int y, int width, int height, boolean raised) { + // Note: lighter/darker colors should be used to draw 3d rect. + // The resulting rect is (width+1)x(height+1). Stroke and paint + // attributes of + // the Graphics2D should be reset to the default values. + // fillRect is used instead of drawLine to bypass stroke + // reset/set and rasterization. - public void drawString(String s, int x, int y) { - this.androidCanvas.drawText(s, x, y, androidPaint); - } - - public void dispose() { - } - - public boolean drawImage(Image image, int x, int y, ImageObserver observer) { - if (image instanceof BufferedImage) { - this.androidCanvas.drawBitmap(((BufferedImage) image).getAndroidBitmap(), (float) x, (float) y, null); + Color color = getColor(); + Color colorUp, colorDown; + if (raised) { + colorUp = color.brighter(); + colorDown = color.darker(); + } else { + colorUp = color.darker(); + colorDown = color.brighter(); } - return true; - } -} + setColor(colorUp); + fillRect(x, y, width, 1); + fillRect(x, y + 1, 1, height); + + setColor(colorDown); + fillRect(x + width, y, 1, height); + fillRect(x + 1, y + height, width, 1); + } + + /** + * Draws the text represented by byte array. This method uses the current + * font and color for rendering. + * + * @param bytes + * the byte array which contains the text to be drawn. + * @param off + * the offset within the byte array of the text to be drawn. + * @param len + * the number of bytes of text to draw. + * @param x + * the X coordinate where the text is to be drawn. + * @param y + * the Y coordinate where the text is to be drawn. + */ + public void drawBytes(byte[] bytes, int off, int len, int x, int y) { + drawString(new String(bytes, off, len), x, y); + } + + /** + * Draws the text represented by character array. This method uses the + * current font and color for rendering. + * + * @param chars + * the character array. + * @param off + * the offset within the character array of the text to be drawn. + * @param len + * the number of characters which will be drawn. + * @param x + * the X coordinate where the text is to be drawn. + * @param y + * the Y coordinate where the text is to be drawn. + */ + public void drawChars(char[] chars, int off, int len, int x, int y) { + drawString(new String(chars, off, len), x, y); + } + + /** + * Draws the outline of a polygon which is defined by Polygon object. + * + * @param p + * the Polygon object. + */ + public void drawPolygon(Polygon p) { + drawPolygon(p.xpoints, p.ypoints, p.npoints); + } + + /** + * Draws the rectangle with the specified width and length and top left + * corner coordinates. + * + * @param x + * the X coordinate of the rectangle's top left corner. + * @param y + * the Y coordinate of the rectangle's top left corner. + * @param width + * the width of the rectangle. + * @param height + * the height of the rectangle. + */ + public void drawRect(int x, int y, int width, int height) { + int[] xpoints = { + x, x, x + width, x + width + }; + int[] ypoints = { + y, y + height, y + height, y + }; + + drawPolygon(xpoints, ypoints, 4); + } + + /** + * Fills the highlighted outline of a rectangle. + * + * @param x + * the X coordinate of the rectangle's top left corner. + * @param y + * the Y coordinate of the rectangle's top left corner. + * @param width + * the width of the rectangle. + * @param height + * the height of the rectangle. + * @param raised + * a boolean value that determines whether the rectangle is drawn + * as raised or indented. + */ + public void fill3DRect(int x, int y, int width, int height, boolean raised) { + // Note: lighter/darker colors should be used to draw 3d rect. + // The resulting rect is (width)x(height), same as fillRect. + // Stroke and paint attributes of the Graphics2D should be reset + // to the default values. fillRect is used instead of drawLine to + // bypass stroke reset/set and line rasterization. + + Color color = getColor(); + Color colorUp, colorDown; + if (raised) { + colorUp = color.brighter(); + colorDown = color.darker(); + setColor(color); + } else { + colorUp = color.darker(); + colorDown = color.brighter(); + setColor(colorUp); + } + + width--; + height--; + fillRect(x + 1, y + 1, width - 1, height - 1); + + setColor(colorUp); + fillRect(x, y, width, 1); + fillRect(x, y + 1, 1, height); + + setColor(colorDown); + fillRect(x + width, y, 1, height); + fillRect(x + 1, y + height, width, 1); + } + + /** + * Fills the polygon with the current color. + * + * @param p + * the Polygon object. + */ + public void fillPolygon(Polygon p) { + fillPolygon(p.xpoints, p.ypoints, p.npoints); + } + + /** + * Disposes of the Graphics. + */ + @Override + public void finalize() { + } + + /** + * Gets the bounds of the current clipping area as a rectangle and copies it + * to an existing rectangle. + * + * @param r + * a Rectangle object where the current clipping area bounds are + * to be copied. + * @return the bounds of the current clipping area. + */ + public Rectangle getClipBounds(Rectangle r) { + Shape clip = getClip(); + + if (clip != null) { + // TODO: Can we get shape bounds without creating Rectangle object? + Rectangle b = clip.getBounds(); + r.x = b.x; + r.y = b.y; + r.width = b.width; + r.height = b.height; + } + + return r; + } + + /** + * Gets the bounds of the current clipping area as a rectangle. + * + * @return a Rectangle object. + * @deprecated Use {@link #getClipBounds()} + */ + @Deprecated + public Rectangle getClipRect() { + return getClipBounds(); + } + + /** + * Gets the font metrics of the current font. The font metrics object + * contains information about the rendering of a particular font. + * + * @return the font metrics of current font. + */ + public FontMetrics getFontMetrics() { + return getFontMetrics(getFont()); + } + + /** + * Determines whether or not the specified rectangle intersects the current + * clipping area. + * + * @param x + * the X coordinate of the rectangle. + * @param y + * the Y coordinate of the rectangle. + * @param width + * the width of the rectangle. + * @param height + * the height of the rectangle. + * @return true, if the specified rectangle intersects the current clipping + * area, false otherwise. + */ + public boolean hitClip(int x, int y, int width, int height) { + // TODO: Create package private method Rectangle.intersects(int, int, + // int, int); + return getClipBounds().intersects(new Rectangle(x, y, width, height)); + } + + /** + * Returns string which represents this Graphics object. + * + * @return the string which represents this Graphics object. + */ + @Override + public String toString() { + // TODO: Think about string representation of Graphics. + return "Graphics"; //$NON-NLS-1$ + } + + // Abstract methods + + /** + * Clears the specified rectangle. This method fills specified rectangle + * with background color. + * + * @param x + * the X coordinate of the rectangle. + * @param y + * the Y coordinate of the rectangle. + * @param width + * the width of the rectangle. + * @param height + * the height of the rectangle. + */ + public abstract void clearRect(int x, int y, int width, int height); + + /** + * Intersects the current clipping area with a new rectangle. If the current + * clipping area is not defined, the rectangle becomes a new clipping area. + * Rendering operations are only allowed within the new the clipping area. + * + * @param x + * the X coordinate of the rectangle for intersection. + * @param y + * the Y coordinate of the rectangle for intersection. + * @param width + * the width of the rectangle for intersection. + * @param height + * the height of the rectangle for intersection. + */ + public abstract void clipRect(int x, int y, int width, int height); + + /** + * Copies the rectangle area to another area specified by a distance (dx, + * dy) from the original rectangle's location. Positive dx and dy values + * give a new location defined by translation to the right and down from the + * original location, negative dx and dy values - to the left and up. + * + * @param sx + * the X coordinate of the rectangle which will be copied. + * @param sy + * the Y coordinate of the rectangle which will be copied. + * @param width + * the width of the rectangle which will be copied. + * @param height + * the height of the rectangle which will be copied. + * @param dx + * the horizontal distance from the source rectangle's location + * to the copy's location. + * @param dy + * the vertical distance from the source rectangle's location to + * the copy's location. + */ + public abstract void copyArea(int sx, int sy, int width, int height, int dx, int dy); + + /** + * Creates a new copy of this Graphics. + * + * @return a new Graphics context which is a copy of this Graphics. + */ + public abstract Graphics create(); + + /** + * Disposes of the Graphics. This Graphics object can not be used after + * calling this method. + */ + public abstract void dispose(); + + /** + * Draws the arc covering the specified rectangle and using the current + * color. The rectangle is defined by the origin point (X, Y) and dimensions + * (width and height). The arc center is the the center of specified + * rectangle. The angle origin is 3 o'clock position, the positive angle is + * counted as a counter-clockwise rotation, the negative angle is counted as + * clockwise rotation. + * + * @param x + * the X origin coordinate of the rectangle which scales the arc. + * @param y + * the Y origin coordinate of the rectangle which scales the arc. + * @param width + * the width of the rectangle which scales the arc. + * @param height + * the height of the rectangle which scales the arc. + * @param sa + * start angle - the origin angle of arc. + * @param ea + * arc angle - the angular arc value relative to the start angle. + */ + public abstract void drawArc(int x, int y, int width, int height, int sa, int ea); + + /** + * Draws the specified image with the defined background color. The top left + * corner of image will be drawn at point (x, y) in current coordinate + * system. The image loading process notifies the specified Image Observer. + * This method returns true if the image has loaded, otherwise it returns + * false. + * + * @param img + * the image which will be drawn. + * @param x + * the X coordinate of the image top left corner. + * @param y + * the Y coordinate of the image top left corner. + * @param bgcolor + * the background color. + * @param observer + * the ImageObserver object which should be notified about image + * loading process. + * @return true, if loading image is successful or image is null, false + * otherwise. + */ + public abstract boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer); + + /** + * Draws the specified image. The top left corner of image will be drawn at + * point (x, y) in current coordinate system. The image loading process + * notifies the specified Image Observer. This method returns true if the + * image has loaded, otherwise it returns false. + * + * @param img + * the image which will be drawn. + * @param x + * the X coordinate of the image top left corner. + * @param y + * the Y coordinate of the image top left corner. + * @param observer + * the ImageObserver object which should be notified about image + * loading process. + * @return true, if loading image is successful or image is null, otherwise + * false. + */ + public abstract boolean drawImage(Image img, int x, int y, ImageObserver observer); + + /** + * Scales the specified image to fit in the specified rectangle and draws it + * with the defined background color. The top left corner of the image will + * be drawn at the point (x, y) in current coordinate system. The non-opaque + * pixels will be drawn in the background color. The image loading process + * notifies the specified Image Observer. This method returns true if the + * image has loaded, otherwise it returns false. + * + * @param img + * the image which will be drawn. + * @param x + * the X coordinate of the image's top left corner. + * @param y + * the Y coordinate of the image's top left corner. + * @param width + * the width of rectangle which scales the image. + * @param height + * the height of rectangle which scales the image. + * @param bgcolor + * the background color. + * @param observer + * the ImageObserver object which should be notified about image + * loading process. + * @return true, if loading image is successful or image is null, otherwise + * false. + */ + public abstract boolean drawImage(Image img, int x, int y, int width, int height, + Color bgcolor, ImageObserver observer); + + /** + * Scales the specified image to fit in the specified rectangle and draws + * it. The top left corner of the image will be drawn at the point (x, y) in + * current coordinate system. The image loading process notifies the + * specified Image Observer. This method returns true if the image has + * loaded, otherwise it returns false. + * + * @param img + * the image which will be drawn. + * @param x + * the X coordinate of the image top left corner. + * @param y + * the Y coordinate of the image top left corner. + * @param width + * the width of rectangle which scales the image. + * @param height + * the height of rectangle which scales the image. + * @param observer + * the ImageObserver object which should be notified about image + * loading process. + * @return true, if loading image is successful or image is null, otherwise + * false. + */ + public abstract boolean drawImage(Image img, int x, int y, int width, int height, + ImageObserver observer); + + /** + * Scales the specified area of the specified image to fit in the rectangle + * area defined by its corners coordinates and draws the sub-image with the + * specified background color. The sub-image to be drawn is defined by its + * top left corner coordinates (sx1, sy1) and bottom right corner + * coordinates (sx2, sy2) computed with respect to the origin (top left + * corner) of the source image. The non opaque pixels will be drawn in the + * background color. The image loading process notifies specified Image + * Observer. This method returns true if the image has loaded, otherwise it + * returns false. + * + * @param img + * the image which will be drawn. + * @param dx1 + * the X top left corner coordinate of the destination rectangle + * area. + * @param dy1 + * the Y top left corner coordinate of the destination rectangle + * area. + * @param dx2 + * the X bottom right corner coordinate of the destination + * rectangle area. + * @param dy2 + * the Y bottom right corner coordinate of the destination + * rectangle area. + * @param sx1 + * the X top left corner coordinate of the area to be drawn + * within the source image. + * @param sy1 + * the Y top left corner coordinate of the area to be drawn + * within the source image. + * @param sx2 + * the X bottom right corner coordinate of the area to be drawn + * within the source image. + * @param sy2 + * the Y bottom right corner coordinate of the area to be drawn + * within the source image. + * @param bgcolor + * the background color. + * @param observer + * the ImageObserver object which should be notified about image + * loading process. + * @return true, if loading image is successful or image is null, false + * otherwise. + */ + public abstract boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, + int sy1, int sx2, int sy2, Color bgcolor, ImageObserver observer); + + /** + * Scales the specified area of the specified image to fit in the rectangle + * area defined by its corners coordinates and draws the sub-image. The + * sub-image to be drawn is defined by its top left corner coordinates (sx1, + * sy1) and bottom right corner coordinates (sx2, sy2) computed with respect + * to the origin (top left corner) of the source image. The image loading + * process notifies specified Image Observer. This method returns true if + * the image has loaded, otherwise it returns false. + * + * @param img + * the image which will be drawn. + * @param dx1 + * the X top left corner coordinate of the destination rectangle + * area. + * @param dy1 + * the Y top left corner coordinate of the destination rectangle + * area. + * @param dx2 + * the X bottom right corner coordinate of the destination + * rectangle area. + * @param dy2 + * the Y bottom right corner coordinate of the destination + * rectangle area. + * @param sx1 + * the X top left corner coordinate of the area to be drawn + * within the source image. + * @param sy1 + * the Y top left corner coordinate of the area to be drawn + * within the source image. + * @param sx2 + * the X bottom right corner coordinate of the area to be drawn + * within the source image. + * @param sy2 + * the Y bottom right corner coordinate of the area to be drawn + * within the source image. + * @param observer + * the ImageObserver object which should be notified about image + * loading process. + * @return true, if loading image is successful or image is null, false + * otherwise. + */ + public abstract boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, + int sy1, int sx2, int sy2, ImageObserver observer); + + /** + * Draws a line from the point (x1, y1) to the point (x2, y2). This method + * draws the line with current color which can be changed by setColor(Color + * c) method. + * + * @param x1 + * the X coordinate of the first point. + * @param y1 + * the Y coordinate of the first point. + * @param x2 + * the X coordinate of the second point. + * @param y2 + * the Y coordinate of the second point. + */ + public abstract void drawLine(int x1, int y1, int x2, int y2); + + /** + * Draws the outline of an oval to fit in the rectangle defined by the given + * width, height, and top left corner. + * + * @param x + * the X top left corner oval coordinate. + * @param y + * the Y top left corner oval coordinate. + * @param width + * the oval width. + * @param height + * the oval height. + */ + public abstract void drawOval(int x, int y, int width, int height); + + /** + * Draws the outline of a polygon. The polygon vertices are defined by + * points with xpoints[i], ypoints[i] as coordinates. The polygon edges are + * the lines from the points with (xpoints[i-1], ypoints[i-1]) coordinates + * to the points with (xpoints[i], ypoints[i]) coordinates, for 0 < i < + * npoints +1. + * + * @param xpoints + * the array of X coordinates of the polygon vertices. + * @param ypoints + * the array of Y coordinates of the polygon vertices. + * @param npoints + * the number of polygon vertices/points. + */ + public abstract void drawPolygon(int[] xpoints, int[] ypoints, int npoints); + + /** + * Draws a set of connected lines which are defined by the x and y + * coordinate arrays. The polyline is closed if coordinates of the first + * point are the same as coordinates of the last point. + * + * @param xpoints + * the array of X point coordinates. + * @param ypoints + * the array of Y point coordinates. + * @param npoints + * the number of points. + */ + public abstract void drawPolyline(int[] xpoints, int[] ypoints, int npoints); + + /** + * Draws the outline of a rectangle with round corners. + * + * @param x + * the X coordinate of the rectangle's top left corner. + * @param y + * the Y coordinate of the rectangle's top left corner. + * @param width + * the width of the rectangle. + * @param height + * the height of the rectangle. + * @param arcWidth + * the arc width for the corners. + * @param arcHeight + * the arc height for the corners. + */ + public abstract void drawRoundRect(int x, int y, int width, int height, int arcWidth, + int arcHeight); + + /** + * Draws a text defined by an iterator. The iterator should specify the font + * for every character. + * + * @param iterator + * the iterator. + * @param x + * the X coordinate of the first character. + * @param y + * the Y coordinate of the first character. + */ + public abstract void drawString(AttributedCharacterIterator iterator, int x, int y); + + /** + * Draws a text defined by a string. This method draws the text with current + * font and color. + * + * @param str + * the string. + * @param x + * the X coordinate of the first character. + * @param y + * the Y coordinate of the first character. + */ + public abstract void drawString(String str, int x, int y); + + /** + * Fills the arc covering the rectangle and using the current color. The + * rectangle is defined by the origin point (X, Y) and dimensions (width and + * height). The arc center is the the center of specified rectangle. The + * angle origin is at the 3 o'clock position, and a positive angle gives + * counter-clockwise rotation, a negative angle gives clockwise rotation. + * + * @param x + * the X origin coordinate of the rectangle which scales the arc. + * @param y + * the Y origin coordinate of the rectangle which scales the arc. + * @param width + * the width of the rectangle which scales the arc. + * @param height + * the height of the rectangle which scales the arc. + * @param sa + * start angle - the origin angle of arc. + * @param ea + * arc angle - the angular arc value relative to the start angle. + */ + public abstract void fillArc(int x, int y, int width, int height, int sa, int ea); + + /** + * Fills an oval with the current color where the oval is defined by the + * bounding rectangle with the given width, height, and top left corner. + * + * @param x + * the X top left corner oval coordinate. + * @param y + * the Y top left corner oval coordinate. + * @param width + * the oval width. + * @param height + * the oval height. + */ + public abstract void fillOval(int x, int y, int width, int height); + + /** + * Fills a polygon with the current color. The polygon vertices are defined + * by the points with xpoints[i], ypoints[i] as coordinates. The polygon + * edges are the lines from the points with (xpoints[i-1], ypoints[i-1]) + * coordinates to the points with (xpoints[i], ypoints[i]) coordinates, for + * 0 < i < npoints +1. + * + * @param xpoints + * the array of X coordinates of the polygon vertices. + * @param ypoints + * the array of Y coordinates of the polygon vertices. + * @param npoints + * the number of polygon vertices/points. + */ + public abstract void fillPolygon(int[] xpoints, int[] ypoints, int npoints); + + /** + * Fills a rectangle with the current color. The rectangle is defined by its + * width and length and top left corner coordinates. + * + * @param x + * the X coordinate of the rectangle's top left corner. + * @param y + * the Y coordinate of the rectangle's top left corner. + * @param width + * the width of rectangle. + * @param height + * the height of rectangle. + */ + public abstract void fillRect(int x, int y, int width, int height); + + /** + * Fills a round cornered rectangle with the current color. + * + * @param x + * the X coordinate of the top left corner of the bounding + * rectangle. + * @param y + * the Y coordinate of the top left corner of the bounding + * rectangle. + * @param width + * the width of the bounding rectangle. + * @param height + * the height of the bounding rectangle. + * @param arcWidth + * the arc width at the corners. + * @param arcHeight + * the arc height at the corners. + */ + public abstract void fillRoundRect(int x, int y, int width, int height, int arcWidth, + int arcHeight); + + /** + * Gets the clipping area.
+ *
+ * + * @return a Shape object of the clipping area or null if it is not set. + */ + public abstract Shape getClip(); + + /** + * Gets the bounds of the current clipping area as a rectangle. + * + * @return a Rectangle object which represents the bounds of the current + * clipping area. + */ + public abstract Rectangle getClipBounds(); + + /** + * Gets the current color of Graphics. + * + * @return the current color. + */ + public abstract Color getColor(); + + /** + * Gets the current font of Graphics. + * + * @return the current font. + */ + public abstract Font getFont(); + + /** + * Gets the font metrics of the specified font. The font metrics object + * contains information about the rendering of a particular font. + * + * @param font + * the specified font. + * @return the font metrics for the specified font. + */ + public abstract FontMetrics getFontMetrics(Font font); + + /** + * Sets the new clipping area specified by rectangle. The new clipping area + * doesn't depend on the window's visibility. Rendering operations can't be + * performed outside new clipping area. + * + * @param x + * the X coordinate of the new clipping rectangle. + * @param y + * the Y coordinate of the new clipping rectangle. + * @param width + * the width of the new clipping rectangle. + * @param height + * the height of the new clipping rectangle. + */ + public abstract void setClip(int x, int y, int width, int height); + + /** + * Sets the new clipping area to be the area specified by Shape object. The + * new clipping area doesn't depend on the window's visibility. Rendering + * operations can't be performed outside new clipping area. + * + * @param clip + * the Shape object which represents new clipping area. + */ + public abstract void setClip(Shape clip); + + /** + * Sets the current Graphics color. All rendering operations with this + * Graphics will use this color. + * + * @param c + * the new color. + */ + public abstract void setColor(Color c); + + /** + * Sets the current Graphics font. All rendering operations with this + * Graphics will use this font. + * + * @param font + * the new font. + */ + public abstract void setFont(Font font); + + /** + * Sets the paint mode for the Graphics which overwrites all rendering + * operations with the current color. + */ + public abstract void setPaintMode(); + + /** + * Sets the XOR mode for the Graphics which changes a pixel from the current + * color to the specified XOR color.
+ *
+ * + * @param color + * the new XOR mode. + */ + public abstract void setXORMode(Color color); + + /** + * Translates the origin of Graphics current coordinate system to the point + * with X, Y coordinates in the current coordinate system. All rendering + * operation in this Graphics will be related to the new origin. + * + * @param x + * the X coordinate of the origin. + * @param y + * the Y coordinate of the origin. + */ + public abstract void translate(int x, int y); +} diff --git a/app/src/main/java/java/awt/Graphics2D.java b/app/src/main/java/java/awt/Graphics2D.java index 3fa43d584..04a7319de 100644 --- a/app/src/main/java/java/awt/Graphics2D.java +++ b/app/src/main/java/java/awt/Graphics2D.java @@ -1,10 +1,513 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package java.awt; +import java.awt.font.GlyphVector; +import java.awt.font.FontRenderContext; +import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; +import java.awt.image.BufferedImageOp; +import java.awt.image.ImageObserver; +import java.awt.image.RenderedImage; +import java.awt.image.renderable.RenderableImage; +import java.text.AttributedCharacterIterator; +import java.util.Map; -public class Graphics2D extends Graphics { - public Graphics2D(BufferedImage bufImage) { - super(bufImage); +/** + * The Graphics2D class extends Graphics class and provides more capabilities + * for rendering text, images, shapes. This provides methods to perform + * transformation of coordinate system, color management, and text layout. The + * following attributes exist for rendering: + *

    + *
  • Color - current Graphics2D color;
  • + *
  • Font - current Graphics2D font;
  • + *
  • Stroke - pen with a width of 1 pixel;
  • + *
  • Transform - current Graphics2D Transformation;
  • + *
  • Composite - alpha compositing rules for combining source and destination + * colors.
  • + *
+ * + * @since Android 1.0 + */ +public abstract class Graphics2D extends Graphics { + + /** + * Instantiates a new Graphics2D object. This constructor should never be + * called directly. + */ + protected Graphics2D() { + super(); } -} + /** + * Adds preferences for the rendering algorithms. The preferences are + * arbitrary and specified by Map objects. All specified by Map object + * preferences can be modified. + * + * @param hints + * the rendering hints. + */ + public abstract void addRenderingHints(Map hints); + + /** + * Intersects the current clipping area with the specified Shape and the + * result becomes a new clipping area. If current clipping area is not + * defined, the Shape becomes the new clipping area. No rendering operations + * are allowed outside the clipping area. + * + * @param s + * the specified Shape object which will be intersected with + * current clipping area. + */ + public abstract void clip(Shape s); + + /** + * Draws the outline of the specified Shape. + * + * @param s + * the Shape which outline is drawn. + */ + public abstract void draw(Shape s); + + /** + * Draws the specified GlyphVector object's text at the point x, y. + * + * @param g + * the GlyphVector object to be drawn. + * @param x + * the X position where the GlyphVector's text should be + * rendered. + * @param y + * the Y position where the GlyphVector's text should be + * rendered. + */ + public abstract void drawGlyphVector(GlyphVector g, float x, float y); + + /** + * Draws the BufferedImage -- modified according to the operation + * BufferedImageOp -- at the point x, y. + * + * @param img + * the BufferedImage to be rendered. + * @param op + * the filter to be applied to the image before rendering. + * @param x + * the X coordinate of the point where the image's upper left + * corner will be placed. + * @param y + * the Y coordinate of the point where the image's upper left + * corner will be placed. + */ + public abstract void drawImage(BufferedImage img, BufferedImageOp op, int x, int y); + + /** + * Draws BufferedImage transformed from image space into user space + * according to the AffineTransform xform and notifies the ImageObserver. + * + * @param img + * the BufferedImage to be rendered. + * @param xform + * the affine transformation from the image to the user space. + * @param obs + * the ImageObserver to be notified about the image conversion. + * @return true, if the image is successfully loaded and rendered, or it's + * null, otherwise false. + */ + public abstract boolean drawImage(Image img, AffineTransform xform, ImageObserver obs); + + /** + * Draws a RenderableImage which is transformed from image space into user + * according to the AffineTransform xform. + * + * @param img + * the RenderableImage to be rendered. + * @param xform + * the affine transformation from image to user space. + */ + public abstract void drawRenderableImage(RenderableImage img, AffineTransform xform); + + /** + * Draws a RenderedImage which is transformed from image space into user + * according to the AffineTransform xform. + * + * @param img + * the RenderedImage to be rendered. + * @param xform + * the affine transformation from image to user space. + */ + public abstract void drawRenderedImage(RenderedImage img, AffineTransform xform); + + /** + * Draws the string specified by the AttributedCharacterIterator. The first + * character's position is specified by the X, Y parameters. + * + * @param iterator + * whose text is drawn. + * @param x + * the X position where the first character is drawn. + * @param y + * the Y position where the first character is drawn. + */ + public abstract void drawString(AttributedCharacterIterator iterator, float x, float y); + + /** + * Draws the string specified by the AttributedCharacterIterator. The first + * character's position is specified by the X, Y parameters. + * + * @param iterator + * whose text is drawn. + * @param x + * the X position where the first character is drawn. + * @param y + * the Y position where the first character is drawn. + * @see java.awt.Graphics#drawString(AttributedCharacterIterator, int, int) + */ + @Override + public abstract void drawString(AttributedCharacterIterator iterator, int x, int y); + + /** + * Draws the String whose the first character position is specified by the + * parameters X, Y. + * + * @param s + * the String to be drawn. + * @param x + * the X position of the first character. + * @param y + * the Y position of the first character. + */ + public abstract void drawString(String s, float x, float y); + + /** + * Draws the String whose the first character coordinates are specified by + * the parameters X, Y. + * + * @param str + * the String to be drawn. + * @param x + * the X coordinate of the first character. + * @param y + * the Y coordinate of the first character. + * @see java.awt.Graphics#drawString(String, int, int) + */ + @Override + public abstract void drawString(String str, int x, int y); + + /** + * Fills the interior of the specified Shape. + * + * @param s + * the Shape to be filled. + */ + public abstract void fill(Shape s); + + /** + * Gets the background color. + * + * @return the current background color. + */ + public abstract Color getBackground(); + + /** + * Gets the current composite of the Graphics2D. + * + * @return the current composite which specifies the compositing style. + */ + public abstract Composite getComposite(); + + /** + * Gets the device configuration. + * + * @return the device configuration. + */ + public abstract GraphicsConfiguration getDeviceConfiguration(); + + /** + * Gets the rendering context of the Font. + * + * @return the FontRenderContext. + */ + public abstract FontRenderContext getFontRenderContext(); + + /** + * Gets the current Paint of Graphics2D. + * + * @return the current Paint of Graphics2D. + */ + public abstract Paint getPaint(); + + /** + * Gets the value of single preference for specified key. + * + * @param key + * the specified key of the rendering hint. + * @return the value of rendering hint for specified key. + */ + public abstract Object getRenderingHint(RenderingHints.Key key); + + /** + * Gets the set of the rendering preferences as a collection of key/value + * pairs. + * + * @return the RenderingHints which contains the rendering preferences. + */ + public abstract RenderingHints getRenderingHints(); + + /** + * Gets current stroke of the Graphics2D. + * + * @return current stroke of the Graphics2D. + */ + public abstract Stroke getStroke(); + + /** + * Gets current affine transform of the Graphics2D. + * + * @return current AffineTransform of the Graphics2D. + */ + public abstract AffineTransform getTransform(); + + /** + * Determines whether or not the specified Shape intersects the specified + * Rectangle. If the onStroke parameter is true, this method checks whether + * or not the specified Shape outline intersects the specified Rectangle, + * otherwise this method checks whether or not the specified Shape's + * interior intersects the specified Rectangle. + * + * @param rect + * the specified Rectangle. + * @param s + * the Shape to check for intersection. + * @param onStroke + * the parameter determines whether or not this method checks for + * intersection of the Shape outline or of the Shape interior + * with the Rectangle. + * @return true, if there is a hit, false otherwise. + */ + public abstract boolean hit(Rectangle rect, Shape s, boolean onStroke); + + /** + * Performs a rotation transform relative to current Graphics2D Transform. + * The coordinate system is rotated by the specified angle in radians + * relative to current origin. + * + * @param theta + * the angle of rotation in radians. + */ + public abstract void rotate(double theta); + + /** + * Performs a translated rotation transform relative to current Graphics2D + * Transform. The coordinate system is rotated by the specified angle in + * radians relative to current origin and then moved to point (x, y). Is + * this right? + * + * @param theta + * the angle of rotation in radians. + * @param x + * the X coordinate. + * @param y + * the Y coordinate. + */ + public abstract void rotate(double theta, double x, double y); + + /** + * Performs a linear scale transform relative to current Graphics2D + * Transform. The coordinate system is rescaled vertically and horizontally + * by the specified parameters. + * + * @param sx + * the scaling factor by which the X coordinate is multiplied. + * @param sy + * the scaling factor by which the Y coordinate is multiplied. + */ + public abstract void scale(double sx, double sy); + + /** + * Sets a new background color for clearing rectangular areas. The clearRect + * method uses the current background color. + * + * @param color + * the new background color. + */ + public abstract void setBackground(Color color); + + /** + * Sets the current composite for Graphics2D. + * + * @param comp + * the Composite object. + */ + public abstract void setComposite(Composite comp); + + /** + * Sets the paint for Graphics2D. + * + * @param paint + * the Paint object. + */ + public abstract void setPaint(Paint paint); + + /** + * Sets a key-value pair in the current RenderingHints map. + * + * @param key + * the key of the rendering hint to set. + * @param value + * the value to set for the rendering hint. + */ + public abstract void setRenderingHint(RenderingHints.Key key, Object value); + + /** + * Replaces the current rendering hints with the specified rendering + * preferences. + * + * @param hints + * the new Map of rendering hints. + */ + public abstract void setRenderingHints(Map hints); + + /** + * Sets the stroke for the Graphics2D. + * + * @param s + * the Stroke object. + */ + public abstract void setStroke(Stroke s); + + /** + * Overwrite the current Transform of the Graphics2D. The specified + * Transform should be received from the getTransform() method and should be + * used only for restoring the original Graphics2D transform after calling + * draw or fill methods. + * + * @param Tx + * the specified Transform. + */ + public abstract void setTransform(AffineTransform Tx); + + /** + * Performs a shear transform relative to current Graphics2D Transform. The + * coordinate system is shifted by the specified multipliers relative to + * current position. + * + * @param shx + * the multiplier by which the X coordinates shift position along + * X axis as a function of Y coordinates. + * @param shy + * the multiplier by which the Y coordinates shift position along + * Y axis as a function of X coordinates. + */ + public abstract void shear(double shx, double shy); + + /** + * Concatenates the AffineTransform object with current Transform of this + * Graphics2D. The transforms are applied in reverse order with the last + * specified transform applied first and the next transformation applied to + * the result of previous transformation. More precisely, if Cx is the + * current Graphics2D transform, the transform method's result with Tx as + * the parameter is the transformation Rx, where Rx(p) = Cx(Tx(p)), for p - + * a point in current coordinate system. Rx becomes the current Transform + * for this Graphics2D. + * + * @param Tx + * the AffineTransform object to be concatenated with current + * Transform. + */ + public abstract void transform(AffineTransform Tx); + + /** + * Performs a translate transform relative to current Graphics2D Transform. + * The coordinate system is moved by the specified distance relative to + * current position. + * + * @param tx + * the translation distance along the X axis. + * @param ty + * the translation distance along the Y axis. + */ + public abstract void translate(double tx, double ty); + + /** + * Moves the origin Graphics2D Transform to the point with x, y coordinates + * in current coordinate system. The new origin of coordinate system is + * moved to the (x, y) point accordingly. All rendering and transform + * operations are performed relative to this new origin. + * + * @param x + * the X coordinate. + * @param y + * the Y coordinate. + * @see java.awt.Graphics#translate(int, int) + */ + @Override + public abstract void translate(int x, int y); + + /** + * Fills a 3D rectangle with the current color. The rectangle is specified + * by its width, height, and top left corner coordinates. + * + * @param x + * the X coordinate of the rectangle's top left corner. + * @param y + * the Y coordinate of the rectangle's top left corner. + * @param width + * the width of rectangle. + * @param height + * the height of rectangle. + * @param raised + * a boolean value that determines whether the rectangle is drawn + * as raised or indented. + * @see java.awt.Graphics#fill3DRect(int, int, int, int, boolean) + */ + @Override + public void fill3DRect(int x, int y, int width, int height, boolean raised) { + // According to the spec, color should be used instead of paint, + // so Graphics.fill3DRect resets paint and + // it should be restored after the call + Paint savedPaint = getPaint(); + super.fill3DRect(x, y, width, height, raised); + setPaint(savedPaint); + } + + /** + * Draws the highlighted outline of a rectangle. + * + * @param x + * the X coordinate of the rectangle's top left corner. + * @param y + * the Y coordinate of the rectangle's top left corner. + * @param width + * the width of rectangle. + * @param height + * the height of rectangle. + * @param raised + * a boolean value that determines whether the rectangle is drawn + * as raised or indented. + * @see java.awt.Graphics#draw3DRect(int, int, int, int, boolean) + */ + @Override + public void draw3DRect(int x, int y, int width, int height, boolean raised) { + // According to the spec, color should be used instead of paint, + // so Graphics.draw3DRect resets paint and + // it should be restored after the call + Paint savedPaint = getPaint(); + super.draw3DRect(x, y, width, height, raised); + setPaint(savedPaint); + } +} \ No newline at end of file diff --git a/app/src/main/java/java/awt/GraphicsConfiguration.java b/app/src/main/java/java/awt/GraphicsConfiguration.java new file mode 100644 index 000000000..d59e896ab --- /dev/null +++ b/app/src/main/java/java/awt/GraphicsConfiguration.java @@ -0,0 +1,226 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey A. Petrenko + * @version $Revision$ + */ + +package java.awt; + +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.VolatileImage; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The GraphicsConfiguration class contains the characteristics of graphics + * devices such as a printer or monitor, and represents device's capabilities + * and modes. Many GraphicsConfiguration objects can be associated with single + * graphics device. + * + * @since Android 1.0 + */ +public abstract class GraphicsConfiguration { + + /** + * Constructor could not be used directly and should be obtained in extended + * classes. + */ + protected GraphicsConfiguration() { + } + + /** + * Creates BufferedImage image object with a data layout and color model + * compatible with this GraphicsConfiguration with specified width and + * height parameters. + * + * @param width + * the width of BufferedImage. + * @param height + * the height of BufferedImage. + * @return the BufferedImage object with specified width and height + * parameters. + */ + public abstract BufferedImage createCompatibleImage(int width, int height); + + /** + * Creates a BufferedImage that has the specified width, height, + * transparency and has a data layout and color model compatible with this + * GraphicsConfiguration. + * + * @param width + * the width of image. + * @param height + * the height of image. + * @param transparency + * the transparency mode. + * @return the BufferedImage object. + */ + public abstract BufferedImage createCompatibleImage(int width, int height, int transparency); + + /** + * Creates a VolatileImage that has the specified width and height and has a + * data layout and color model compatible with this GraphicsConfiguration. + * + * @param width + * the width of image. + * @param height + * the height of image. + * @return the VolatileImage object. + */ + public abstract VolatileImage createCompatibleVolatileImage(int width, int height); + + /** + * Creates a VolatileImage that supports the specified width, height, + * transparency and has a data layout and color model compatible with this + * GraphicsConfiguration. + * + * @param width + * the width of image. + * @param height + * the height of image. + * @param transparency + * the transparency mode. + * @return the VolatileImage object. + */ + public abstract VolatileImage createCompatibleVolatileImage(int width, int height, + int transparency); + + /** + * Gets the bounds of area covered by the GraphicsConfiguration in the + * device coordinates space. + * + * @return the Rectangle of GraphicsConfiguration's bounds. + */ + public abstract Rectangle getBounds(); + + /** + * Gets the ColorModel of the GraphicsConfiguration. + * + * @return the ColorModel object of the GraphicsConfiguration. + */ + public abstract ColorModel getColorModel(); + + /** + * Gets the ColorModel of the GraphicsConfiguration which supports specified + * Transparency. + * + * @param transparency + * the Transparency mode: OPAQUE, BITMASK, or TRANSLUCENT. + * @return the ColorModel of the GraphicsConfiguration which supports + * specified Transparency. + */ + public abstract ColorModel getColorModel(int transparency); + + /** + * Gets the default AffineTransform of the GraphicsConfiguration. This + * method translates user coordinates to device coordinates. + * + * @return the default AffineTransform of the GraphicsConfiguration. + */ + public abstract AffineTransform getDefaultTransform(); + + /** + * Gets the GraphicsDevice of the GraphicsConfiguration. + * + * @return the GraphicsDevice of the GraphicsConfiguration. + */ + public abstract GraphicsDevice getDevice(); + + /** + * Gets the normalizing AffineTransform of the GraphicsConfiguration. + * + * @return the normalizing AffineTransform of the GraphicsConfiguration. + */ + public abstract AffineTransform getNormalizingTransform(); + + /** + * Creates VolatileImage with specified width, height, ImageCapabilities; a + * data layout and color model compatible with this GraphicsConfiguration. + * + * @param width + * the width of image. + * @param height + * the height of image. + * @param caps + * the ImageCapabilities object. + * @return the VolatileImage which data layout and color model compatible + * with this GraphicsConfiguration. + * @throws AWTException + * if ImageCapabilities is not supported by the + * GraphicsConfiguration. + */ + public VolatileImage createCompatibleVolatileImage(int width, int height, ImageCapabilities caps) + throws AWTException { + VolatileImage res = createCompatibleVolatileImage(width, height); + if (!res.getCapabilities().equals(caps)) { + // awt.14A=Can not create VolatileImage with specified capabilities + throw new AWTException(Messages.getString("awt.14A")); //$NON-NLS-1$ + } + return res; + } + + /** + * Creates a VolatileImage with specified width, height, transparency and + * ImageCapabilities; a data layout and color model compatible with this + * GraphicsConfiguration. + * + * @param width + * the width of image. + * @param height + * the height of image. + * @param caps + * the ImageCapabilities object. + * @param transparency + * the Transparency mode: OPAQUE, BITMASK, or TRANSLUCENT. + * @return the VolatileImage which data layout and color model compatible + * with this GraphicsConfiguration. + * @throws AWTException + * if ImageCapabilities is not supported by the + * GraphicsConfiguration. + */ + public VolatileImage createCompatibleVolatileImage(int width, int height, + ImageCapabilities caps, int transparency) throws AWTException { + VolatileImage res = createCompatibleVolatileImage(width, height, transparency); + if (!res.getCapabilities().equals(caps)) { + // awt.14A=Can not create VolatileImage with specified capabilities + throw new AWTException(Messages.getString("awt.14A")); //$NON-NLS-1$ + } + return res; + } + + /** + * Gets the buffering capabilities of the GraphicsConfiguration. + * + * @return the BufferCapabilities object. + */ + public BufferCapabilities getBufferCapabilities() { + return new BufferCapabilities(new ImageCapabilities(false), new ImageCapabilities(false), + BufferCapabilities.FlipContents.UNDEFINED); + } + + /** + * Gets the image capabilities of the GraphicsConfiguration. + * + * @return the ImageCapabilities object. + */ + public ImageCapabilities getImageCapabilities() { + return new ImageCapabilities(false); + } +} diff --git a/app/src/main/java/java/awt/GraphicsDevice.java b/app/src/main/java/java/awt/GraphicsDevice.java new file mode 100644 index 000000000..9eda4e0ed --- /dev/null +++ b/app/src/main/java/java/awt/GraphicsDevice.java @@ -0,0 +1,196 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey A. Petrenko + * @version $Revision$ + */ + +package java.awt; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The GraphicsDevice class describes the graphics devices (such as screens or + * printers) which are available in a particular graphics environment. Many + * GraphicsDevice instances can be associated with a single GraphicsEnvironment. + * Each GraphicsDevice has one or more GraphicsConfiguration objects which + * specify the different configurations and modes of GraphicsDevice. + * + * @since Android 1.0 + */ +public abstract class GraphicsDevice { + + /** + * The display mode. + */ + private DisplayMode displayMode; + + // ???AWT + // private Window fullScreenWindow = null; + + /** + * The Constant TYPE_IMAGE_BUFFER indicates a image buffer device. + */ + + public static final int TYPE_IMAGE_BUFFER = 2; + + /** + * The Constant TYPE_PRINTER indicates a printer device. + */ + public static final int TYPE_PRINTER = 1; + + /** + * The Constant TYPE_RASTER_SCREEN indicates a raster screen device. + */ + public static final int TYPE_RASTER_SCREEN = 0; + + /** + * Constructor is not to be used directly as this class is abstract. + */ + protected GraphicsDevice() { + displayMode = new DisplayMode(0, 0, DisplayMode.BIT_DEPTH_MULTI, + DisplayMode.REFRESH_RATE_UNKNOWN); + } + + /** + * Returns an array of GraphicsConfiguration objects associated with the + * GraphicsDevice. + * + * @return an array of GraphicsConfiguration objects associated with the + * GraphicsDevice. + */ + public abstract GraphicsConfiguration[] getConfigurations(); + + /** + * Gets the default configuration for the GraphicsDevice. + * + * @return the default GraphicsConfiguration object for the GraphicsDevice. + */ + public abstract GraphicsConfiguration getDefaultConfiguration(); + + /** + * Gets the String identifier which associated with the GraphicsDevice in + * the GraphicsEnvironment. + * + * @return the String identifier of the GraphicsDevice in the + * GraphicsEnvironment. + */ + public abstract String getIDstring(); + + /** + * Gets the type of this GraphicsDevice: TYPE_IMAGE_BUFFER, TYPE_PRINTER or + * TYPE_RASTER_SCREEN. + * + * @return the type of this GraphicsDevice: TYPE_IMAGE_BUFFER, TYPE_PRINTER + * or TYPE_RASTER_SCREEN. + */ + public abstract int getType(); + + /** + * Returns the number of bytes available in accelerated memory on this + * device. + * + * @return the number of bytes available accelerated memory. + */ + public int getAvailableAcceleratedMemory() { + return 0; + } + + /* + * ???AWT public GraphicsConfiguration + * getBestConfiguration(GraphicsConfigTemplate gct) { return + * gct.getBestConfiguration(getConfigurations()); } + */ + + /** + * Gets the current display mode of the GraphicsDevice. + * + * @return the current display mode of the GraphicsDevice. + */ + public DisplayMode getDisplayMode() { + return displayMode; + } + + /** + * Gets an array of display modes available in this GraphicsDevice. + * + * @return an array of display modes available in this GraphicsDevice. + */ + public DisplayMode[] getDisplayModes() { + DisplayMode[] dms = { + displayMode + }; + return dms; + } + + /* + * ???AWT public Window getFullScreenWindow() { return fullScreenWindow; } + */ + + /** + * Returns true if this GraphicsDevice supports low-level display changes. + * + * @return true, if this GraphicsDevice supports low-level display changes; + * false otherwise. + */ + public boolean isDisplayChangeSupported() { + return false; + } + + /** + * Returns true if this GraphicsDevice supports full screen mode. + * + * @return true, if this GraphicsDevice supports full screen mode, false + * otherwise. + */ + public boolean isFullScreenSupported() { + return false; + } + + // an array of display modes available in this GraphicsDevice. + + /** + * Sets the display mode of this GraphicsDevice. + * + * @param dm + * the new display mode of this GraphicsDevice. + */ + public void setDisplayMode(DisplayMode dm) { + if (!isDisplayChangeSupported()) { + // awt.122=Does not support display mode changes + throw new UnsupportedOperationException(Messages.getString("awt.122")); //$NON-NLS-1$ + } + + DisplayMode[] dms = getDisplayModes(); + for (DisplayMode element : dms) { + if (element.equals(dm)) { + displayMode = dm; + return; + } + } + // awt.123=Unsupported display mode: {0} + throw new IllegalArgumentException(Messages.getString("awt.123", dm)); //$NON-NLS-1$ + } + + /* + * ???AWT public void setFullScreenWindow(Window w) { if (w == null) { + * fullScreenWindow = null; return; } fullScreenWindow = w; if + * (isFullScreenSupported()) { w.enableInputMethods(false); } else { + * w.setSize(displayMode.getWidth(), displayMode.getHeight()); + * w.setLocation(0, 0); } w.setVisible(true); w.setAlwaysOnTop(true); } + */ +} diff --git a/app/src/main/java/java/awt/GraphicsEnvironment.java b/app/src/main/java/java/awt/GraphicsEnvironment.java index e776f4ede..d527417f7 100644 --- a/app/src/main/java/java/awt/GraphicsEnvironment.java +++ b/app/src/main/java/java/awt/GraphicsEnvironment.java @@ -1,27 +1,212 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ + package java.awt; -/* - * A fake GraphicsEnvironment, it was added - * for AWT codes compatible and do nothing. +import java.awt.image.BufferedImage; +import java.util.Locale; + +import org.apache.harmony.awt.ContextStorage; +import org.apache.harmony.awt.gl.CommonGraphics2DFactory; + +/** + * The GraphicsEnvironment class defines a collection of GraphicsDevice objects + * and Font objects which are available for Java application on current + * platform. + * + * @since Android 1.0 */ -public class GraphicsEnvironment extends Object -{ - private static GraphicsEnvironment localEnv = new GraphicsEnvironment(); - public static GraphicsEnvironment getLocalGraphicsEnvironment() { - return localEnv; - } - - public static String getHeadlessMessage() { - return - "\nNo X11 DISPLAY variable was set, " + - "but this program performed an operation which requires it."; +public abstract class GraphicsEnvironment { + + /** + * Constructor could not be used directly and should be obtained in extended + * classes. + */ + protected GraphicsEnvironment() { } - - public static void checkHeadless() { - - } - - public static boolean isHeadless() { + + /** + * Gets the local GraphicsEnvironment. + * + * @return the local GraphicsEnvironment. + */ + public static GraphicsEnvironment getLocalGraphicsEnvironment() { + synchronized (ContextStorage.getContextLock()) { + if (ContextStorage.getGraphicsEnvironment() == null) { + if (isHeadless()) { + ContextStorage.setGraphicsEnvironment(new HeadlessGraphicsEnvironment()); + } else { + CommonGraphics2DFactory g2df = (CommonGraphics2DFactory)Toolkit + .getDefaultToolkit().getGraphicsFactory(); + + ContextStorage.setGraphicsEnvironment(g2df + .createGraphicsEnvironment(ContextStorage.getWindowFactory())); + } + } + + return ContextStorage.getGraphicsEnvironment(); + } + } + + /** + * Returns whether or not a display, keyboard, and mouse are supported in + * this graphics environment. + * + * @return true, if HeadlessException will be thrown from areas of the + * graphics environment that are dependent on a display, keyboard, + * or mouse, false otherwise. + */ + public boolean isHeadlessInstance() { return false; } + + /** + * Checks whether or not a display, keyboard, and mouse are supported in + * this environment. + * + * @return true, if a HeadlessException is thrown from areas of the Toolkit + * and GraphicsEnvironment that are dependent on a display, + * keyboard, or mouse, false otherwise. + */ + public static boolean isHeadless() { + return "true".equals(System.getProperty("java.awt.headless")); + } + + /** + * Gets the maximum bounds of system centered windows. + * + * @return the maximum bounds of system centered windows. + * @throws HeadlessException + * if isHeadless() method returns true. + */ + public Rectangle getMaximumWindowBounds() throws HeadlessException { + return getDefaultScreenDevice().getDefaultConfiguration().getBounds(); + } + + /** + * Gets the Point which should defines the center of system window. + * + * @return the Point where the system window should be centered. + * @throws HeadlessException + * if isHeadless() method returns true. + */ + public Point getCenterPoint() throws HeadlessException { + Rectangle mwb = getMaximumWindowBounds(); + return new Point(mwb.width >> 1, mwb.height >> 1); + } + + /** + * Indicates that the primary font should be used. Primary font is specified + * by initial system locale or default encoding). + */ + public void preferLocaleFonts() { + // Note: API specification says following: + // "The actual change in font rendering behavior resulting + // from a call to this method is implementation dependent; + // it may have no effect at all." So, doing nothing is an + // acceptable behavior for this method. + + // For now FontManager uses 1.4 font.properties scheme for font mapping, + // so + // this method doesn't make any sense. The implementation of this method + // which will influence font mapping is postponed until + // 1.5 mapping scheme not implemented. + + // todo - Implement non-default behavior with 1.5 font mapping scheme + } + + /** + * Indicates that a proportional preference of the font should be used. + */ + public void preferProportionalFonts() { + // Note: API specification says following: + // "The actual change in font rendering behavior resulting + // from a call to this method is implementation dependent; + // it may have no effect at all." So, doing nothing is an + // acceptable behavior for this method. + + // For now FontManager uses 1.4 font.properties scheme for font mapping, + // so + // this method doesn't make any sense. The implementation of this method + // which will influence font mapping is postponed until + // 1.5 mapping scheme not implemented. + + // todo - Implement non-default behavior with 1.5 font mapping scheme + } + + /** + * Creates the Graphics2D object for rendering to the specified + * BufferedImage. + * + * @param bufferedImage + * the BufferedImage object. + * @return the Graphics2D object which allows to render to the specified + * BufferedImage. + */ + public abstract Graphics2D createGraphics(BufferedImage bufferedImage); + + /** + * Gets the array of all available fonts instances in this + * GraphicsEnviroments. + * + * @return the array of all available fonts instances in this + * GraphicsEnviroments. + */ + public abstract Font[] getAllFonts(); + + /** + * Gets the array of all available font family names. + * + * @return the array of all available font family names. + */ + public abstract String[] getAvailableFontFamilyNames(); + + /** + * Gets the array of all available font family names for the specified + * locale. + * + * @param locale + * the Locale object which represents geographical region. The + * default locale is used if locale is null. + * @return the array of available font family names for the specified + * locale. + */ + public abstract String[] getAvailableFontFamilyNames(Locale locale); + + /** + * Gets the default screen device as GraphicDevice object. + * + * @return the GraphicDevice object which represents default screen device. + * @throws HeadlessException + * if isHeadless() returns true. + */ + public abstract GraphicsDevice getDefaultScreenDevice() throws HeadlessException; + + /** + * Gets an array of all available screen devices. + * + * @return the array of GraphicsDevice objects which represents all + * available screen devices. + * @throws HeadlessException + * if isHeadless() returns true. + */ + public abstract GraphicsDevice[] getScreenDevices() throws HeadlessException; } diff --git a/app/src/main/java/java/awt/HeadlessException.java b/app/src/main/java/java/awt/HeadlessException.java index fb9515879..ec111f1e4 100644 --- a/app/src/main/java/java/awt/HeadlessException.java +++ b/app/src/main/java/java/awt/HeadlessException.java @@ -1,54 +1,54 @@ /* - * Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. + * http://www.apache.org/licenses/LICENSE-2.0 * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ -package java.awt; /** - * Thrown when code that is dependent on a keyboard, display, or mouse - * is called in an environment that does not support a keyboard, display, - * or mouse. - * - * @since 1.4 - * @author Michael Martak + * @author Alexey A. Petrenko + * @version $Revision$ + */ + +package java.awt; + +/** + * The HeadlessException class provides notifications and error messages when + * code that is dependent on a keyboard, display, or mouse is called in an + * environment that does not support a keyboard, display, or mouse. + * + * @since Android 1.0 */ public class HeadlessException extends UnsupportedOperationException { - /* - * JDK 1.4 serialVersionUID + + /** + * The Constant serialVersionUID. */ private static final long serialVersionUID = 167183644944358563L; - public HeadlessException() {} + + /** + * Instantiates a new headless exception. + */ + public HeadlessException() { + super(); + } + + /** + * Instantiates a new headless exception with the specified message. + * + * @param msg + * the String which represents error message. + */ public HeadlessException(String msg) { super(msg); } - public String getMessage() { - String superMessage = super.getMessage(); - String headlessMessage = GraphicsEnvironment.getHeadlessMessage(); - if (superMessage == null) { - return headlessMessage; - } else if (headlessMessage == null) { - return superMessage; - } else { - return superMessage + headlessMessage; - } - } } diff --git a/app/src/main/java/java/awt/HeadlessGraphicsEnvironment.java b/app/src/main/java/java/awt/HeadlessGraphicsEnvironment.java new file mode 100644 index 000000000..306393f33 --- /dev/null +++ b/app/src/main/java/java/awt/HeadlessGraphicsEnvironment.java @@ -0,0 +1,72 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.awt; + +import java.awt.GraphicsDevice; +import java.awt.HeadlessException; + +import org.apache.harmony.awt.gl.CommonGraphicsEnvironment; + +/** + * The HeadlessGraphicsEnvironment class is the CommonGraphicsEnvironment + * implementation to use in the case where the environment lacks display, + * keyboard, and mouse support. + * + * @since Android 1.0 + */ +public class HeadlessGraphicsEnvironment extends CommonGraphicsEnvironment { + + /** + * Returns whether or not a display, keyboard, and mouse are supported in + * this graphics environment. + * + * @return true, if HeadlessException will be thrown from areas of the + * graphics environment that are dependent on a display, keyboard, + * or mouse, false otherwise. + */ + @Override + public boolean isHeadlessInstance() { + return true; + } + + /** + * Gets the default screen device as GraphicDevice object. + * + * @return the GraphicDevice object which represents default screen device. + * @throws HeadlessException + * if isHeadless() returns true. + */ + @Override + public GraphicsDevice getDefaultScreenDevice() throws HeadlessException { + throw new HeadlessException(); + } + + /** + * Gets an array of all available screen devices. + * + * @return the array of GraphicsDevice objects which represents all + * available screen devices. + * @throws HeadlessException + * if isHeadless() returns true. + */ + @Override + public GraphicsDevice[] getScreenDevices() throws HeadlessException { + throw new HeadlessException(); + } + +} diff --git a/app/src/main/java/java/awt/HeadlessToolkit.java b/app/src/main/java/java/awt/HeadlessToolkit.java new file mode 100644 index 000000000..f652ce3bd --- /dev/null +++ b/app/src/main/java/java/awt/HeadlessToolkit.java @@ -0,0 +1,226 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.awt; + +//???AWT +//import java.awt.datatransfer.Clipboard; +//import java.awt.dnd.DragGestureEvent; +//import java.awt.dnd.DragGestureListener; +//import java.awt.dnd.DragGestureRecognizer; +//import java.awt.dnd.DragSource; +//import java.awt.dnd.InvalidDnDOperationException; +//import java.awt.dnd.peer.DragSourceContextPeer; +import java.awt.datatransfer.*; +import java.awt.im.*; +import java.awt.image.*; +import java.util.*; +import org.apache.harmony.awt.*; +import org.apache.harmony.awt.wtk.*; + +/** + * The HeadlessToolkit class is a subclass of ToolkitImpl to be used for + * graphical environments that lack keyboard and mouse capabilities. + * + * @since Android 1.0 + */ +public final class HeadlessToolkit extends ToolkitImpl { + + // ???AWT + /* + * @Override protected ButtonPeer createButton(Button a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected CheckboxPeer createCheckbox(Checkbox a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected CheckboxMenuItemPeer + * createCheckboxMenuItem(CheckboxMenuItem a0) throws HeadlessException { + * throw new HeadlessException(); } + * @Override protected ChoicePeer createChoice(Choice a0) throws + * HeadlessException { throw new HeadlessException(); } public Cursor + * createCustomCursor(Image img, Point hotSpot, String name) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected DialogPeer createDialog(Dialog a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override public T + * createDragGestureRecognizer( Class recognizerAbstractClass, DragSource + * ds, Component c, int srcActions, DragGestureListener dgl) { return null; + * } + * @Override public DragSourceContextPeer + * createDragSourceContextPeer(DragGestureEvent dge) throws + * InvalidDnDOperationException { throw new InvalidDnDOperationException(); + * } + * @Override protected FileDialogPeer createFileDialog(FileDialog a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected FramePeer createFrame(Frame a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected LabelPeer createLabel(Label a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected ListPeer createList(List a0) throws HeadlessException + * { throw new HeadlessException(); } + * @Override protected MenuPeer createMenu(Menu a0) throws HeadlessException + * { throw new HeadlessException(); } + * @Override protected MenuBarPeer createMenuBar(MenuBar a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected MenuItemPeer createMenuItem(MenuItem a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected PopupMenuPeer createPopupMenu(PopupMenu a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected ScrollbarPeer createScrollbar(Scrollbar a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected ScrollPanePeer createScrollPane(ScrollPane a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected TextAreaPeer createTextArea(TextArea a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected TextFieldPeer createTextField(TextField a0) throws + * HeadlessException { throw new HeadlessException(); } + * @Override protected WindowPeer createWindow(Window a0) throws + * HeadlessException { throw new HeadlessException(); } + */ + + @Override + public Dimension getBestCursorSize(int prefWidth, int prefHeight) throws HeadlessException { + throw new HeadlessException(); + } + + @Override + public Clipboard getSystemClipboard() throws HeadlessException { + throw new HeadlessException(); + } + + @Override + public ColorModel getColorModel() throws HeadlessException { + throw new HeadlessException(); + } + + @Override + public GraphicsFactory getGraphicsFactory() throws HeadlessException { + throw new HeadlessException(); + } + + @Override + public boolean getLockingKeyState(int keyCode) throws UnsupportedOperationException { + throw new HeadlessException(); + } + + @Override + public int getMaximumCursorColors() throws HeadlessException { + throw new HeadlessException(); + } + + @Override + public int getMenuShortcutKeyMask() throws HeadlessException { + throw new HeadlessException(); + } + + // ???AWT + /* + * @Override NativeEventQueue getNativeEventQueue() throws HeadlessException + * { throw new HeadlessException(); } + * @Override public PrintJob getPrintJob(Frame frame, String jobtitle, + * JobAttributes jobAttributes, PageAttributes pageAttributes) throws + * IllegalArgumentException { throw new IllegalArgumentException(); } + * @Override public PrintJob getPrintJob(Frame frame, String jobtitle, + * Properties props) throws NullPointerException { throw new + * NullPointerException(); } + */ + + @Override + public Insets getScreenInsets(GraphicsConfiguration gc) throws HeadlessException { + throw new HeadlessException(); + } + + @Override + public int getScreenResolution() throws HeadlessException { + throw new HeadlessException(); + } + + @Override + public Dimension getScreenSize() throws HeadlessException { + throw new HeadlessException(); + } + + // ???AWT + /* + * @Override public Clipboard getSystemClipboard() throws HeadlessException + * { throw new HeadlessException(); } + * @Override public Clipboard getSystemSelection() throws HeadlessException + * { throw new HeadlessException(); } + * @Override WindowFactory getWindowFactory() throws HeadlessException { + * throw new HeadlessException(); } + */ + + @Override + protected void init() { + lockAWT(); + try { + ComponentInternals.setComponentInternals(new ComponentInternalsImpl()); + // ???AWT: new EventQueue(this); // create the system EventQueue + // ???AWT: dispatcher = new Dispatcher(this); + desktopProperties = new HashMap(); + // ???AWT: desktopPropsSupport = new PropertyChangeSupport(this); + // ???AWT: awtEventsManager = new AWTEventsManager(); + // ???AWT: dispatchThread = new HeadlessEventDispatchThread(this, + // dispatcher); + // ???AWT: dtk = DTK.getDTK(); + dispatchThread.start(); + } finally { + unlockAWT(); + } + } + + @Override + public boolean isDynamicLayoutActive() throws HeadlessException { + throw new HeadlessException(); + } + + @Override + protected boolean isDynamicLayoutSet() throws HeadlessException { + throw new HeadlessException(); + } + + @Override + public boolean isFrameStateSupported(int state) throws HeadlessException { + throw new HeadlessException(); + } + + @Override + protected void loadSystemColors(int[] systemColors) throws HeadlessException { + throw new HeadlessException(); + } + + @Override + public Map mapInputMethodHighlight( + InputMethodHighlight highlight) throws HeadlessException { + throw new HeadlessException(); + } + + @Override + Map mapInputMethodHighlightImpl(InputMethodHighlight highlight) + throws HeadlessException { + throw new HeadlessException(); + } + + @Override + public void setDynamicLayout(boolean dynamic) throws HeadlessException { + throw new HeadlessException(); + } + + @Override + public void setLockingKeyState(int keyCode, boolean on) throws UnsupportedOperationException { + throw new HeadlessException(); + } +} diff --git a/app/src/main/java/java/awt/Image.java b/app/src/main/java/java/awt/Image.java index 4c5efff85..7ae3ed883 100644 --- a/app/src/main/java/java/awt/Image.java +++ b/app/src/main/java/java/awt/Image.java @@ -1,6 +1,205 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + package java.awt; -public abstract class Image -{ - // MOD: Fake class. +import java.awt.image.AreaAveragingScaleFilter; +import java.awt.image.FilteredImageSource; +import java.awt.image.ImageFilter; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.image.ReplicateScaleFilter; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Image abstract class represents the graphic images. + * + * @since Android 1.0 + */ +public abstract class Image { + + /** + * The UndefinedProperty object should be returned if property is not + * defined for a particular image. + */ + public static final Object UndefinedProperty = new Object(); // $NON-LOCK-1$ + + /** + * The Constant SCALE_DEFAULT indicates the default image scaling algorithm. + */ + public static final int SCALE_DEFAULT = 1; + + /** + * The Constant SCALE_FAST indicates an image scaling algorithm which places + * a higher priority on scaling speed than on the image's smoothness. + */ + public static final int SCALE_FAST = 2; + + /** + * The Constant SCALE_SMOOTH indicates an image scaling algorithm which + * places a higher priority on image smoothness than on scaling speed. + */ + public static final int SCALE_SMOOTH = 4; + + /** + * The Constant SCALE_REPLICATE indicates the image scaling algorithm in the + * ReplicateScaleFilter class. + */ + public static final int SCALE_REPLICATE = 8; + + /** + * The Constant SCALE_AREA_AVERAGING indicates the area averaging image + * scaling algorithm. + */ + public static final int SCALE_AREA_AVERAGING = 16; + + /** + * The acceleration priority indicates image acceleration. + */ + protected float accelerationPriority = 0.5f; + + /** + * The Constant capabilities. + */ + private static final ImageCapabilities capabilities = new ImageCapabilities(false); + + /** + * Gets the image property with the specified name. The UndefinedProperty + * object should be return if the property is not specified for this image. + * The return value should be null if the property is currently unknown yet + * and the specified ImageObserver is to be notified later. + * + * @param name + * the name of image's property. + * @param observer + * the ImageObserver. + * @return the Object which represents value of the specified property. + */ + public abstract Object getProperty(String name, ImageObserver observer); + + /** + * Gets the ImageProducer object which represents data of this Image. + * + * @return the ImageProducer object which represents data of this Image. + */ + public abstract ImageProducer getSource(); + + /** + * Gets the width of this image. The specified ImageObserver object is + * notified when the width of this image is available. + * + * @param observer + * the ImageObserver object which is is notified when the width + * of this image is available. + * @return the width of image, or -1 if the width of this image is not + * available. + */ + public abstract int getWidth(ImageObserver observer); + + /** + * Gets the height of this image. The specified ImageObserver object is + * notified when the height of this image is available. + * + * @param observer + * the ImageObserver object which is is notified when the height + * of this image is available. + * @return the height of image, or -1 if the height of this image is not + * available. + */ + public abstract int getHeight(ImageObserver observer); + + /** + * Gets the scaled instance of this Image. This method returns an Image + * object constructed from the source of this image with the specified + * width, height, and applied scaling algorithm. + * + * @param width + * the width of scaled Image. + * @param height + * the height of scaled Image. + * @param hints + * the constant which indicates scaling algorithm. + * @return the scaled Image. + */ + public Image getScaledInstance(int width, int height, int hints) { + ImageFilter filter; + if ((hints & (SCALE_SMOOTH | SCALE_AREA_AVERAGING)) != 0) { + filter = new AreaAveragingScaleFilter(width, height); + } else { + filter = new ReplicateScaleFilter(width, height); + } + ImageProducer producer = new FilteredImageSource(getSource(), filter); + return Toolkit.getDefaultToolkit().createImage(producer); + } + + /** + * Gets a Graphics object for rendering this image. This method can be used + * for off-screen images. + * + * @return a Graphics object for rendering to this image. + */ + public abstract Graphics getGraphics(); + + /** + * Flushes resources which are used by this Image object. This method resets + * the image to the reconstructed state from the image's source. + */ + public abstract void flush(); + + /** + * Gets the acceleration priority of this image. + * + * @return the acceleration priority of this image. + */ + public float getAccelerationPriority() { + return accelerationPriority; + } + + /** + * Sets the acceleration priority for this image. + * + * @param priority + * the new acceleration priority (value in the range 0-1). + */ + public void setAccelerationPriority(float priority) { + if (priority < 0 || priority > 1) { + // awt.10A=Priority must be a value between 0 and 1, inclusive + throw new IllegalArgumentException(Messages.getString("awt.10A")); //$NON-NLS-1$ + } + accelerationPriority = priority; + } + + /** + * Gets an ImageCapabilities object of this Image object for the specified + * GraphicsConfiguration. + * + * @param gc + * the specified GraphicsConfiguration object (null value means + * default GraphicsConfiguration). + * @return an ImageCapabilities object of this Image object for the + * specified GraphicsConfiguration. + */ + public ImageCapabilities getCapabilities(GraphicsConfiguration gc) { + // Note: common image is not accelerated. + return capabilities; + } } diff --git a/app/src/main/java/java/awt/ImageCapabilities.java b/app/src/main/java/java/awt/ImageCapabilities.java new file mode 100644 index 000000000..c6d59462a --- /dev/null +++ b/app/src/main/java/java/awt/ImageCapabilities.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey A. Petrenko + * @version $Revision$ + */ + +package java.awt; + +/** + * The ImageCapabilities class gives information about an image's capabilities. + * + * @since Android 1.0 + */ +public class ImageCapabilities implements Cloneable { + + /** + * The accelerated. + */ + private final boolean accelerated; + + /** + * Instantiates a new ImageCapabilities with the specified acceleration flag + * which indicates whether acceleration is desired or not. + * + * @param accelerated + * the accelerated flag. + */ + public ImageCapabilities(boolean accelerated) { + this.accelerated = accelerated; + } + + /** + * Returns a copy of this ImageCapabilities object. + * + * @return the copy of this ImageCapabilities object. + */ + @Override + public Object clone() { + return new ImageCapabilities(accelerated); + } + + /** + * Returns true if the Image of this ImageCapabilities is or can be + * accelerated. + * + * @return true, if the Image of this ImageCapabilities is or can be + * accelerated, false otherwise. + */ + public boolean isAccelerated() { + return accelerated; + } + + /** + * Returns true if this ImageCapabilities applies to the VolatileImage which + * can lose its surfaces. + * + * @return true if this ImageCapabilities applies to the VolatileImage which + * can lose its surfaces, false otherwise. + */ + public boolean isTrueVolatile() { + return true; + } +} diff --git a/app/src/main/java/java/awt/ItemSelectable.java b/app/src/main/java/java/awt/ItemSelectable.java new file mode 100644 index 000000000..212cf709e --- /dev/null +++ b/app/src/main/java/java/awt/ItemSelectable.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ + +package java.awt; + +import java.awt.event.ItemListener; + +/** + * The ItemSelectable interface represents a set of items which can be selected. + * + * @since Android 1.0 + */ +public interface ItemSelectable { + + /** + * Adds an ItemListener for receiving item events when the state of an item + * is changed by the user. + * + * @param l + * the ItemListener. + */ + public void addItemListener(ItemListener l); + + /** + * Gets an array of the selected objects or null if there is no selected + * object. + * + * @return an array of the selected objects or null if there is no selected + * object. + */ + public Object[] getSelectedObjects(); + + /** + * Removes the specified ItemListener. + * + * @param l + * the ItemListener which will be removed. + */ + public void removeItemListener(ItemListener l); + +} diff --git a/app/src/main/java/java/awt/MenuComponent.java b/app/src/main/java/java/awt/MenuComponent.java new file mode 100644 index 000000000..9c1b120e6 --- /dev/null +++ b/app/src/main/java/java/awt/MenuComponent.java @@ -0,0 +1,783 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.awt; + +import java.awt.event.FocusListener; +import java.awt.event.MouseEvent; +import java.awt.peer.MenuComponentPeer; +import java.io.Serializable; +import java.util.Locale; //import javax.accessibility.Accessible; +//import javax.accessibility.AccessibleComponent; +//import javax.accessibility.AccessibleContext; +//import javax.accessibility.AccessibleRole; +//import javax.accessibility.AccessibleSelection; +//import javax.accessibility.AccessibleStateSet; +import org.apache.harmony.awt.gl.MultiRectArea; +import org.apache.harmony.awt.state.MenuItemState; +import org.apache.harmony.awt.state.MenuState; +import org.apache.harmony.luni.util.NotImplementedException; + +/** + * The MenuComponent abstract class is the superclass for menu components. Menu + * components receive and process AWT events. + * + * @since Android 1.0 + */ +public abstract class MenuComponent implements Serializable { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = -4536902356223894379L; + + /** + * The name. + */ + private String name; + + /** + * The font. + */ + private Font font; + + /** + * The parent. + */ + MenuContainer parent; + + /** + * The deprecated event handler. + */ + boolean deprecatedEventHandler = true; + + /** + * The selected item index. + */ + private int selectedItemIndex; + + // ???AWT: private AccessibleContext accessibleContext; + + /** + * The toolkit. + */ + final Toolkit toolkit = Toolkit.getDefaultToolkit(); + + // ???AWT + /* + * protected abstract class AccessibleAWTMenuComponent extends + * AccessibleContext implements Serializable, AccessibleComponent, + * AccessibleSelection { private static final long serialVersionUID = + * -4269533416223798698L; public void addFocusListener(FocusListener + * listener) { } public boolean contains(Point pt) { return false; } public + * Accessible getAccessibleAt(Point pt) { return null; } public Color + * getBackground() { return null; } public Rectangle getBounds() { return + * null; } public Cursor getCursor() { return null; } public Font getFont() + * { return MenuComponent.this.getFont(); } public FontMetrics + * getFontMetrics(Font font) { return null; } public Color getForeground() { + * return null; } public Point getLocation() { return null; } public Point + * getLocationOnScreen() { return null; } public Dimension getSize() { + * return null; } public boolean isEnabled() { return true; // always + * enabled } public boolean isFocusTraversable() { return true; // always + * focus traversable } public boolean isShowing() { return true;// always + * showing } public boolean isVisible() { return true; // always visible } + * public void removeFocusListener(FocusListener listener) { } public void + * requestFocus() { } public void setBackground(Color color) { } public void + * setBounds(Rectangle rect) { } public void setCursor(Cursor cursor) { } + * public void setEnabled(boolean enabled) { } public void setFont(Font + * font) { MenuComponent.this.setFont(font); } public void + * setForeground(Color color) { } public void setLocation(Point pt) { } + * public void setSize(Dimension pt) { } public void setVisible(boolean + * visible) { } public void addAccessibleSelection(int index) { } public + * void clearAccessibleSelection() { } public Accessible + * getAccessibleSelection(int index) { return null; } public int + * getAccessibleSelectionCount() { return 0; } public boolean + * isAccessibleChildSelected(int index) { return false; } public void + * removeAccessibleSelection(int index) { } public void + * selectAllAccessibleSelection() { } + * @Override public Accessible getAccessibleChild(int index) { return null; + * } + * @Override public int getAccessibleChildrenCount() { return 0; } + * @Override public AccessibleComponent getAccessibleComponent() { return + * this; } + * @Override public String getAccessibleDescription() { return + * super.getAccessibleDescription(); } + * @Override public int getAccessibleIndexInParent() { toolkit.lockAWT(); + * try { Accessible aParent = getAccessibleParent(); int aIndex = -1; if + * (aParent instanceof MenuComponent) { MenuComponent parent = + * (MenuComponent) aParent; int count = parent.getItemCount(); for (int i = + * 0; i < count; i++) { MenuComponent comp = parent.getItem(i); if (comp + * instanceof Accessible) { aIndex++; if (comp == MenuComponent.this) { + * return aIndex; } } } } return -1; } finally { toolkit.unlockAWT(); } } + * @Override public String getAccessibleName() { return + * super.getAccessibleName(); } + * @Override public Accessible getAccessibleParent() { toolkit.lockAWT(); + * try { Accessible aParent = super.getAccessibleParent(); if (aParent != + * null) { return aParent; } MenuContainer parent = getParent(); if (parent + * instanceof Accessible) { aParent = (Accessible) parent; } return aParent; + * } finally { toolkit.unlockAWT(); } } + * @Override public AccessibleRole getAccessibleRole() { return + * AccessibleRole.AWT_COMPONENT; } + * @Override public AccessibleSelection getAccessibleSelection() { return + * this; } + * @Override public AccessibleStateSet getAccessibleStateSet() { return new + * AccessibleStateSet(); } + * @Override public Locale getLocale() { return Locale.getDefault(); } } + */ + + /** + * The accessor to MenuComponent internal state, utilized by the visual + * theme. + * + * @throws HeadlessException + * the headless exception. + */ + // ???AWT + /* + * class State implements MenuState { Dimension size; Dimension getSize() { + * if (size == null) { calculate(); } return size; } public int getWidth() { + * return getSize().width; } public int getHeight() { return + * getSize().height; } public Font getFont() { return + * MenuComponent.this.getFont(); } public int getItemCount() { return + * MenuComponent.this.getItemCount(); } public int getSelectedItemIndex() { + * return MenuComponent.this.getSelectedItemIndex(); } public boolean + * isFontSet() { return MenuComponent.this.isFontSet(); } + * @SuppressWarnings("deprecation") public FontMetrics getFontMetrics(Font + * f) { return MenuComponent.this.toolkit.getFontMetrics(f); } public Point + * getLocation() { return MenuComponent.this.getLocation(); } public + * MenuItemState getItem(int index) { MenuItem item = + * MenuComponent.this.getItem(index); return item.itemState; } public void + * setSize(int w, int h) { this.size = new Dimension(w, h); } void + * calculate() { size = new Dimension(); + * size.setSize(toolkit.theme.calculateMenuSize(this)); } void reset() { for + * (int i = 0; i < getItemCount(); i++) { ((MenuItem.State) + * getItem(i)).reset(); } } } + */ + + /** + * Pop-up box for menu. It transfers the paint events, keyboard and mouse + * events to the menu component itself. + */ + // ???AWT + /* + * class MenuPopupBox extends PopupBox { private final Point lastMousePos = + * new Point(); + * @Override boolean isMenu() { return true; } + * @Override void paint(Graphics gr) { MenuComponent.this.paint(gr); } + * @Override void onKeyEvent(int eventId, int vKey, long when, int + * modifiers) { MenuComponent.this.onKeyEvent(eventId, vKey, when, + * modifiers); } + * @Override void onMouseEvent(int eventId, Point where, int mouseButton, + * long when, int modifiers, int wheelRotation) { // prevent conflict of + * mouse and keyboard // when sub-menu drops down due to keyboard navigation + * if (lastMousePos.equals(where) && (eventId == MouseEvent.MOUSE_MOVED || + * eventId == MouseEvent.MOUSE_ENTERED)) { return; } + * lastMousePos.setLocation(where); MenuComponent.this.onMouseEvent(eventId, + * where, mouseButton, when, modifiers); } } + */ + + /** + * Instantiates a new MenuComponent object. + * + * @throws HeadlessException + * if the graphical interface environment can't support + * MenuComponents. + */ + public MenuComponent() throws HeadlessException { + toolkit.lockAWT(); + try { + Toolkit.checkHeadless(); + name = autoName(); + selectedItemIndex = -1; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the name of the MenuComponent object. + * + * @return the name of the MenuComponent object. + */ + public String getName() { + toolkit.lockAWT(); + try { + return name; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Returns a String representation of the MenuComponent object. + * + * @return a String representation of the MenuComponent object. + */ + @Override + public String toString() { + toolkit.lockAWT(); + try { + return getClass().getName() + "[" + paramString() + "]"; //$NON-NLS-1$ //$NON-NLS-2$ + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Gets the parent menu container. + * + * @return the parent. + */ + public MenuContainer getParent() { + toolkit.lockAWT(); + try { + return parent; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Sets the name of the MenuComponent to the specified string. + * + * @param name + * the new name of the MenuComponent object. + */ + public void setName(String name) { + toolkit.lockAWT(); + try { + this.name = name; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Dispatches AWT event. + * + * @param event + * the AWTEvent. + */ + public final void dispatchEvent(AWTEvent event) { + toolkit.lockAWT(); + try { + processEvent(event); + if (deprecatedEventHandler) { + postDeprecatedEvent(event); + } + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Post deprecated event. + * + * @param event + * the event. + */ + void postDeprecatedEvent(AWTEvent event) { + Event evt = event.getEvent(); + if (evt != null) { + postEvent(evt); + } + } + + /** + * Gets the peer of the MenuComponent; an application must not use this + * method directly. + * + * @return the MenuComponentPeer object. + * @throws NotImplementedException + * if this method is not implemented by a subclass. + * @deprecated an application must not use this method directly. + */ + @Deprecated + public MenuComponentPeer getPeer() throws org.apache.harmony.luni.util.NotImplementedException { + toolkit.lockAWT(); + try { + } finally { + toolkit.unlockAWT(); + } + if (true) { + throw new RuntimeException("Method is not implemented"); //TODO: implement //$NON-NLS-1$ + } + return null; + } + + /** + * Gets the locking object of this MenuComponent. + * + * @return the locking object of this MenuComponent. + */ + protected final Object getTreeLock() { + return toolkit.awtTreeLock; + } + + /** + * Posts the Event to the MenuComponent. + * + * @param e + * the Event. + * @return true, if the event is posted successfully, false otherwise. + * @deprecated Replaced dispatchEvent method. + */ + @SuppressWarnings("deprecation") + @Deprecated + public boolean postEvent(Event e) { + toolkit.lockAWT(); + try { + if (parent != null) { + return parent.postEvent(e); + } + return false; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Returns the string representation of the MenuComponent state. + * + * @return returns the string representation of the MenuComponent state. + */ + protected String paramString() { + toolkit.lockAWT(); + try { + return getName(); + } finally { + toolkit.unlockAWT(); + } + } + + // ???AWT + /* + * public AccessibleContext getAccessibleContext() { toolkit.lockAWT(); try + * { if (accessibleContext == null) { accessibleContext = + * createAccessibleContext(); } return accessibleContext; } finally { + * toolkit.unlockAWT(); } } + */ + + /** + * Gets the font of the MenuComponent object. + * + * @return the Font of the MenuComponent object. + */ + public Font getFont() { + toolkit.lockAWT(); + try { + if (font == null && hasDefaultFont()) { + return toolkit.getDefaultFont(); + } + if (font == null && parent != null) { + return parent.getFont(); + } + return font; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Checks if is font set. + * + * @return true, if is font set + */ + boolean isFontSet() { + return font != null + || ((parent instanceof MenuComponent) && ((MenuComponent)parent).isFontSet()); + } + + /** + * Checks for default font. + * + * @return true, if successful. + */ + boolean hasDefaultFont() { + return false; + } + + /** + * Processes an AWTEevent on this menu component. + * + * @param event + * the AWTEvent. + */ + protected void processEvent(AWTEvent event) { + toolkit.lockAWT(); + try { + // do nothing + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Removes the peer of the MenuComponent. + */ + public void removeNotify() { + toolkit.lockAWT(); + try { + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Sets the Font for this MenuComponent object. + * + * @param font + * the new Font to be used for this MenuComponent. + */ + public void setFont(Font font) { + toolkit.lockAWT(); + try { + this.font = font; + } finally { + toolkit.unlockAWT(); + } + } + + /** + * Sets the parent. + * + * @param parent + * the new parent. + */ + void setParent(MenuContainer parent) { + this.parent = parent; + } + + /** + * Gets the location. + * + * @return the location. + */ + Point getLocation() { + // to be overridden + return new Point(0, 0); + } + + /** + * Gets the width. + * + * @return the width. + */ + int getWidth() { + // to be overridden + return 1; + } + + /** + * Gets the height. + * + * @return the height. + */ + int getHeight() { + // to be overridden + return 1; + } + + /** + * Recursively find the menu item for a menu shortcut. + * + * @param gr + * the gr. + * @return the menu item; or null if the item is not available for this + * shortcut. + */ + // ???AWT + /* + * MenuItem getShortcutMenuItemImpl(MenuShortcut ms) { if (ms == null) { + * return null; } for (int i = 0; i < getItemCount(); i++) { MenuItem mi = + * getItem(i); if (mi instanceof Menu) { mi = ((Menu) + * mi).getShortcutMenuItemImpl(ms); if (mi != null) { return mi; } } else if + * (ms.equals(mi.getShortcut())) { return mi; } } return null; } + */ + + void paint(Graphics gr) { + gr.setColor(Color.LIGHT_GRAY); + gr.fillRect(0, 0, getWidth(), getHeight()); + gr.setColor(Color.BLACK); + } + + /** + * Mouse events handler. + * + * @param eventId + * one of the MouseEvent.MOUSE_* constants. + * @param where + * mouse location. + * @param mouseButton + * mouse button that was pressed or released. + * @param when + * event time. + * @param modifiers + * input event modifiers. + */ + void onMouseEvent(int eventId, Point where, int mouseButton, long when, int modifiers) { + // to be overridden + } + + /** + * Keyboard event handler. + * + * @param eventId + * one of the KeyEvent.KEY_* constants. + * @param vKey + * the key code. + * @param when + * event time. + * @param modifiers + * input event modifiers. + */ + void onKeyEvent(int eventId, int vKey, long when, int modifiers) { + // to be overridden + } + + /** + * Post the ActionEvent or ItemEvent, depending on type of the menu item. + * + * @param index + * the index. + * @return the item rect. + */ + // ???AWT + /* + * void fireItemAction(int item, long when, int modifiers) { MenuItem mi = + * getItem(item); mi.itemSelected(when, modifiers); } MenuItem getItem(int + * index) { // to be overridden return null; } int getItemCount() { return + * 0; } + */ + + /** + * @return The sub-menu of currently selecetd item, or null if such a + * sub-menu is not available. + */ + // ???AWT + /* + * Menu getSelectedSubmenu() { if (selectedItemIndex < 0) { return null; } + * MenuItem item = getItem(selectedItemIndex); return (item instanceof Menu) + * ? (Menu) item : null; } + */ + + /** + * Convenience method for selectItem(index, true). + */ + // ???AWT + /* + * void selectItem(int index) { selectItem(index, true); } + */ + + /** + * Change the selection in the menu. + * + * @param index + * new selecetd item's index. + * @param showSubMenu + * if new selected item has a sub-menu, should that sub-menu be + * displayed. + */ + // ???AWT + /* + * void selectItem(int index, boolean showSubMenu) { if (selectedItemIndex + * == index) { return; } if (selectedItemIndex >= 0 && + * getItem(selectedItemIndex) instanceof Menu) { ((Menu) + * getItem(selectedItemIndex)).hide(); } MultiRectArea clip = + * getUpdateClip(index, selectedItemIndex); selectedItemIndex = index; + * Graphics gr = getGraphics(clip); if (gr != null) { paint(gr); } if + * (showSubMenu) { showSubMenu(selectedItemIndex); } } + */ + + /** + * Change the selected item to the next one in the requested direction + * moving cyclically, skipping separators + * + * @param forward + * the direction to move the selection. + * @param showSubMenu + * if new selected item has a sub-menu, should that sub-menu be + * displayed. + */ + // ???AWT + /* + * void selectNextItem(boolean forward, boolean showSubMenu) { int selected + * = getSelectedItemIndex(); int count = getItemCount(); if (count == 0) { + * return; } if (selected < 0) { selected = (forward ? count - 1 : 0); } int + * i = selected; do { i = (forward ? (i + 1) : (i + count - 1)) % count; i + * %= count; MenuItem item = getItem(i); if (!"-".equals(item.getLabel())) { + * //$NON-NLS-1$ selectItem(i, showSubMenu); return; } } while (i != + * selected); } void showSubMenu(int index) { if ((index < 0) || + * !isActive()) { return; } MenuItem item = getItem(index); if (item + * instanceof Menu) { Menu menu = ((Menu) getItem(index)); if + * (menu.getItemCount() == 0) { return; } Point location = + * getSubmenuLocation(index); menu.show(location.x, location.y, false); } } + */ + + /** + * @return the menu bar which is the root of current menu's hierarchy; or + * null if the hierarchy root is not a menu bar. + */ + // ???AWT + /* + * MenuBar getMenuBar() { if (parent instanceof MenuBar) { return (MenuBar) + * parent; } if (parent instanceof MenuComponent) { return ((MenuComponent) + * parent).getMenuBar(); } return null; } PopupBox getPopupBox() { return + * null; } + */ + + Rectangle getItemRect(int index) { + // to be overridden + return null; + } + + /** + * Determine the clip region when menu selection is changed from index1 to + * index2. + * + * @param index1 + * old selected item. + * @param index2 + * new selected item. + * @return the region to repaint. + */ + final MultiRectArea getUpdateClip(int index1, int index2) { + MultiRectArea clip = new MultiRectArea(); + if (index1 >= 0) { + clip.add(getItemRect(index1)); + } + if (index2 >= 0) { + clip.add(getItemRect(index2)); + } + return clip; + } + + /** + * Gets the submenu location. + * + * @param index + * the index. + * @return the submenu location. + */ + Point getSubmenuLocation(int index) { + // to be overridden + return new Point(0, 0); + } + + /** + * Gets the selected item index. + * + * @return the selected item index. + */ + int getSelectedItemIndex() { + return selectedItemIndex; + } + + /** + * Hide. + */ + void hide() { + selectedItemIndex = -1; + if (parent instanceof MenuComponent) { + ((MenuComponent)parent).itemHidden(this); + } + } + + /** + * Item hidden. + * + * @param mc + * the mc. + */ + void itemHidden(MenuComponent mc) { + // to be overridden + } + + /** + * Checks if is visible. + * + * @return true, if is visible. + */ + boolean isVisible() { + return true; + } + + /** + * Checks if is active. + * + * @return true, if is active. + */ + boolean isActive() { + return true; + } + + /** + * Hide all menu hierarchy. + */ + void endMenu() { + // ???AWT: toolkit.dispatcher.popupDispatcher.deactivateAll(); + } + + /** + * Handle the mouse click or Enter key event on a menu's item. + * + * @param when + * the event time. + * @param modifiers + * input event modifiers. + */ + void itemSelected(long when, int modifiers) { + endMenu(); + } + + /** + * Auto name. + * + * @return the string. + */ + String autoName() { + String name = getClass().getName(); + if (name.indexOf("$") != -1) { //$NON-NLS-1$ + return null; + } + // ???AWT: int number = toolkit.autoNumber.nextMenuComponent++; + int number = 0; + name = name.substring(name.lastIndexOf(".") + 1) + Integer.toString(number); //$NON-NLS-1$ + return name; + } + + /** + * Creates the Graphics object for the pop-up box of this menu component. + * + * @param clip + * the clip to set on this Graphics. + * @return the created Graphics object, or null if such object is not + * available. + */ + Graphics getGraphics(MultiRectArea clip) { + // to be overridden + return null; + } + + /** + * @return accessible context specific for particular menu component. + */ + // ???AWT + /* + * AccessibleContext createAccessibleContext() { return null; } + */ +} diff --git a/app/src/main/java/java/awt/MenuContainer.java b/app/src/main/java/java/awt/MenuContainer.java new file mode 100644 index 000000000..e509a1b1b --- /dev/null +++ b/app/src/main/java/java/awt/MenuContainer.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ + +package java.awt; + +/** + * The MenuContainer interface represents all menu containers. + * + * @since Android 1.0 + */ +public interface MenuContainer { + + /** + * Removes the specified MenuComponent from the MenuContainer. + * + * @param c + * the MenuComponent. + */ + public void remove(MenuComponent c); + + /** + * Gets the Font of the MenuContainer. + * + * @return the font of the MenuContainer. + */ + public Font getFont(); + + /** + * Posts an Event. + * + * @param e + * the Event. + * @return true if the event is posted successfully, false otherwise. + * @deprecated Replaced by dispatchEvent method. + */ + @Deprecated + public boolean postEvent(Event e); + +} diff --git a/app/src/main/java/java/awt/ModalContext.java b/app/src/main/java/java/awt/ModalContext.java new file mode 100644 index 000000000..32a591200 --- /dev/null +++ b/app/src/main/java/java/awt/ModalContext.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt; + +/** + * + * The context for nested event loop. It can be dialog, popup menu etc. + */ +class ModalContext { + + private boolean running = false; + + private final Toolkit toolkit; + + ModalContext() { + toolkit = Toolkit.getDefaultToolkit(); + } + + /** + * Set up and run modal loop in this context + * + */ + void runModalLoop() { + running = true; + toolkit.dispatchThread.runModalLoop(this); + } + + /** + * Leave the modal loop running in this context + * This method doesn't stops the loop immediately, + * it just sets the flag that says the modal loop to stop + * + */ + void endModalLoop() { + running = false; + } + + /** + * + * @return modal loop is currently running in this context + */ + boolean isModalLoopRunning() { + return running; + } + +} diff --git a/app/src/main/java/java/awt/MouseDispatcher.java b/app/src/main/java/java/awt/MouseDispatcher.java new file mode 100644 index 000000000..df48f9d61 --- /dev/null +++ b/app/src/main/java/java/awt/MouseDispatcher.java @@ -0,0 +1,418 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Dmitry A. Durnev, Michael Danilov, Pavel Dolgov + * @version $Revision$ + */ +package java.awt; + +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; +import java.awt.Dispatcher.MouseGrabManager; +import java.util.EventListener; + +import org.apache.harmony.awt.wtk.NativeEvent; +import org.apache.harmony.awt.wtk.NativeWindow; + + +class MouseDispatcher { + + // Fields for synthetic mouse click events generation + private static final int clickDelta = 5; + private final long[] lastPressTime = new long[] {0l, 0l, 0l}; + private final Point[] lastPressPos = new Point[] {null, null, null}; + private final boolean[] buttonPressed = new boolean[] {false, false, false}; + private final int[] clickCount = new int[] {0, 0, 0}; + + // Fields for mouse entered/exited support + private Component lastUnderPointer = null; + private final Point lastScreenPos = new Point(-1, -1); + + // Fields for redundant mouse moved/dragged filtering + private Component lastUnderMotion = null; + private Point lastLocalPos = new Point(-1, -1); + + private final MouseGrabManager mouseGrabManager; + private final Toolkit toolkit; + + static Point convertPoint(Component src, int x, int y, Component dest) { + Point srcPoint = getAbsLocation(src); + Point destPoint = getAbsLocation(dest); + + return new Point(x + (srcPoint.x - destPoint.x), + y + (srcPoint.y - destPoint.y)); + } + + static Point convertPoint(Component src, Point p, Component dst) { + return convertPoint(src, p.x, p.y, dst); + } + + private static Point getAbsLocation(Component comp) { + Point location = new Point(0, 0); +// BEGIN android-changed: AWT components not supported +// for (Component parent = comp; parent != null; parent = parent.parent) { +// Point parentPos = (parent instanceof EmbeddedWindow ? +// parent.getNativeWindow().getScreenPos() : +// parent.getLocation()); +// +// location.translate(parentPos.x, parentPos.y); +// +// if (parent instanceof Window) { +// break; +// } +// } +// END android-changed + + return location; + } + + MouseDispatcher(MouseGrabManager mouseGrabManager, + Toolkit toolkit) { + this.mouseGrabManager = mouseGrabManager; + this.toolkit = toolkit; + } + + Point getPointerPos() { + return lastScreenPos; + } + + boolean dispatch(Component src, NativeEvent event) { + int id = event.getEventId(); + + lastScreenPos.setLocation(event.getScreenPos()); + checkMouseEnterExit(event.getInputModifiers(), event.getTime()); + + if (id == MouseEvent.MOUSE_WHEEL) { +// BEGIN android-changed: AWT components not supported +// dispatchWheelEvent(src, event); +// END android-changed + } else if ((id != MouseEvent.MOUSE_ENTERED) && + (id != MouseEvent.MOUSE_EXITED)) { + PointerInfo info = new PointerInfo(src, event.getLocalPos()); + + mouseGrabManager.preprocessEvent(event); + findEventSource(info); + if ((id == MouseEvent.MOUSE_PRESSED) || + (id == MouseEvent.MOUSE_RELEASED)) { + + dispatchButtonEvent(info, event); + } else if ((id == MouseEvent.MOUSE_MOVED) || + (id == MouseEvent.MOUSE_DRAGGED)) { + + dispatchMotionEvent(info, event); + } + } + + return false; + } + + private void checkMouseEnterExit(int modifiers, long when) { +// BEGIN android-changed: AWT components not supported +// PointerInfo info = findComponentUnderPointer(); +// Component curUnderPointer = +// propagateEvent(info, AWTEvent.MOUSE_EVENT_MASK, +// MouseListener.class, false).src; +// +// if (curUnderPointer != lastUnderPointer) { +// Point pos = info.position; +// if ((lastUnderPointer != null) && +// lastUnderPointer.isMouseExitedExpected()) { +// +// Point exitPos = convertPoint(null, lastScreenPos.x, +// lastScreenPos.y, lastUnderPointer); +// +// postMouseEnterExit(MouseEvent.MOUSE_EXITED, modifiers, when, +// exitPos.x, exitPos.y, lastUnderPointer); +// } +// setCursor(curUnderPointer); +// if (curUnderPointer != null) { +// postMouseEnterExit(MouseEvent.MOUSE_ENTERED, modifiers, when, +// pos.x, pos.y, curUnderPointer); +// } +// lastUnderPointer = curUnderPointer; +// } +// END android-changed + } + + private void setCursor(Component comp) { + if (comp == null) { + return; + } + Component grabOwner = mouseGrabManager.getSyntheticGrabOwner(); + Component cursorComp = ((grabOwner != null) && + grabOwner.isShowing() ? grabOwner : comp); + cursorComp.setCursor(); + } + + private void postMouseEnterExit(int id, int mod, long when, + int x, int y, Component comp) { + if (comp.isIndirectlyEnabled()) { + toolkit.getSystemEventQueueImpl().postEvent( + new MouseEvent(comp, id, when, mod, x, y, 0, false)); + comp.setMouseExitedExpected(id == MouseEvent.MOUSE_ENTERED); + } else { + comp.setMouseExitedExpected(false); + } + } + + // BEGIN android-changed: AWT components not supported +// private PointerInfo findComponentUnderPointer() { +// NativeWindow nativeWindow = toolkit.getWindowFactory(). +// getWindowFromPoint(lastScreenPos); +// +// if (nativeWindow != null) { +// Component comp = toolkit.getComponentById(nativeWindow.getId()); +// +// if (comp != null) { +// Window window = comp.getWindowAncestor(); +// Point pointerPos = convertPoint(null, lastScreenPos.x, +// lastScreenPos.y, window); +// +// if (window.getClient().contains(pointerPos)) { +// PointerInfo info = new PointerInfo(window, pointerPos); +// +// fall2Child(info); +// +// return info; +// } +// } +// } +// +// return new PointerInfo(null, null); +// } +// END android-changed + + private void findEventSource(PointerInfo info) { + Component grabOwner = mouseGrabManager.getSyntheticGrabOwner(); + + if (grabOwner != null && grabOwner.isShowing()) { + info.position = convertPoint(info.src, info.position, grabOwner); + info.src = grabOwner; + } else { + //???AWT: rise2TopLevel(info); + //???AWT: fall2Child(info); + } + } + + // BEGIN android-changed: AWT components not supported +// private void rise2TopLevel(PointerInfo info) { +// while (!(info.src instanceof Window)) { +// info.position.translate(info.src.x, info.src.y); +// info.src = info.src.parent; +// } +// } +// +// private void fall2Child(PointerInfo info) { +// Insets insets = info.src.getInsets(); +// +// final Point pos = info.position; +// final int x = pos.x; +// final int y = pos.y; +// if ((x >= insets.left) && (y >= insets.top) && +// (x < (info.src.w - insets.right)) && +// (y < (info.src.h - insets.bottom))) +// { +// Component[] children = ((Container) info.src).getComponents(); +// +// for (Component child : children) { +// if (child.isShowing()) { +// if (child.contains(x - child.getX(), +// y - child.getY())) +// { +// info.src = child; +// pos.translate(-child.x, -child.y); +// +// if (child instanceof Container) { +// fall2Child(info); +// } +// +// return; +// } +// } +// } +// } +// } +// END android-changed + + private void dispatchButtonEvent(PointerInfo info, NativeEvent event) { + int button = event.getMouseButton(); + long time = event.getTime(); + int id = event.getEventId(); + int index = button - 1; + boolean clickRequired = false; + + propagateEvent(info, AWTEvent.MOUSE_EVENT_MASK, + MouseListener.class, false); + if (id == MouseEvent.MOUSE_PRESSED) { + int clickInterval = toolkit.dispatcher.clickInterval; + mouseGrabManager.onMousePressed(info.src); + buttonPressed[index] = true; + clickCount[index] = (!deltaExceeded(index, info) && + ((time - lastPressTime[index]) <= clickInterval)) ? + clickCount[index] + 1 : 1; + lastPressTime[index] = time; + lastPressPos[index] = info.position; + } else { + mouseGrabManager.onMouseReleased(info.src); + // set cursor back on synthetic mouse grab end: +// BEGIN android-changed: AWT components not supported +// setCursor(findComponentUnderPointer().src); +// END android-changed + if (buttonPressed[index]) { + buttonPressed[index] = false; + clickRequired = !deltaExceeded(index, info); + } else { + clickCount[index] = 0; + } + } + if (info.src.isIndirectlyEnabled()) { + final Point pos = info.position; + final int mod = event.getInputModifiers(); + toolkit.getSystemEventQueueImpl().postEvent( + new MouseEvent(info.src, id, time, mod, pos.x, + pos.y, clickCount[index], + event.getTrigger(), button)); + if (clickRequired) { + toolkit.getSystemEventQueueImpl().postEvent( + new MouseEvent(info.src, + MouseEvent.MOUSE_CLICKED, + time, mod, pos.x, pos.y, + clickCount[index], false, + button)); + } + } + } + + private boolean deltaExceeded(int index, PointerInfo info) { + final Point lastPos = lastPressPos[index]; + if (lastPos == null) { + return true; + } + return ((Math.abs(lastPos.x - info.position.x) > clickDelta) || + (Math.abs(lastPos.y - info.position.y) > clickDelta)); + } + + private void dispatchMotionEvent(PointerInfo info, NativeEvent event) { + propagateEvent(info, AWTEvent.MOUSE_MOTION_EVENT_MASK, + MouseMotionListener.class, false); + final Point pos = info.position; + if ((lastUnderMotion != info.src) || + !lastLocalPos.equals(pos)) { + + lastUnderMotion = info.src; + lastLocalPos = pos; + + if (info.src.isIndirectlyEnabled()) { + toolkit.getSystemEventQueueImpl().postEvent( + new MouseEvent(info.src, event.getEventId(), + event.getTime(), + event.getInputModifiers(), + pos.x, pos.y, 0, false)); + } + } + } + + MouseWheelEvent createWheelEvent(Component src, NativeEvent event, + Point where) { + + Integer scrollAmountProperty = + (Integer)toolkit.getDesktopProperty("awt.wheelScrollingSize"); //$NON-NLS-1$ + int amount = 1; + int type = MouseWheelEvent.WHEEL_UNIT_SCROLL; + + if (scrollAmountProperty != null) { + amount = scrollAmountProperty.intValue(); + if (amount == -1) { + type = MouseWheelEvent.WHEEL_BLOCK_SCROLL; + amount = 1; + } + } + return new MouseWheelEvent(src, event.getEventId(), + event.getTime(), event.getInputModifiers(), + where.x, where.y, 0, false, type, amount, + event.getWheelRotation()); + } + +// BEGIN android-changed: AWT components not supported +// private void dispatchWheelEvent(Component src, NativeEvent event) { +// PointerInfo info = findComponentUnderPointer(); +// +// if (info.src == null) { +// info.src = src; +// info.position = event.getLocalPos(); +// } +// +// propagateEvent(info, AWTEvent.MOUSE_WHEEL_EVENT_MASK, +// MouseWheelListener.class, true); +// if ((info.src != null) && info.src.isIndirectlyEnabled()) { +// toolkit.getSystemEventQueueImpl().postEvent( +// createWheelEvent(info.src, event, info.position)); +// } +// } +// END android-changed + + private PointerInfo propagateEvent(PointerInfo info, long mask, + Class type, boolean pierceHW) { + Component src = info.src; + while ((src != null) && + (src.isLightweight() || pierceHW) && + !(src.isMouseEventEnabled(mask) || + (src.getListeners(type).length > 0))) { + + info.position.translate(src.x, src.y); +// BEGIN android-changed: AWT components not supported +// src = src.parent; +// END android-changed + info.src = src; + } + + return info; + } + +// BEGIN android-changed: AWT components not supported +// Window findWindowAt(Point p) { +// NativeWindow nativeWindow = +// toolkit.getWindowFactory().getWindowFromPoint(p); +// +// Window window = null; +// if (nativeWindow != null) { +// Component comp = toolkit.getComponentById(nativeWindow.getId()); +// +// if (comp != null) { +// window = comp.getWindowAncestor(); +// } +// } +// return window; +// } +// END android-changed + + private class PointerInfo { + + Component src; + Point position; + + PointerInfo(Component src, Point position) { + this.src = src; + this.position = position; + } + + } + +} diff --git a/app/src/main/java/java/awt/Polygon.java b/app/src/main/java/java/awt/Polygon.java index de31eb989..925bfc2d9 100644 --- a/app/src/main/java/java/awt/Polygon.java +++ b/app/src/main/java/java/awt/Polygon.java @@ -198,8 +198,8 @@ public class Polygon implements Shape, Serializable { this.npoints = npoints; this.xpoints = new int[npoints]; this.ypoints = new int[npoints]; - System.arraycopy(xpoints, 0, this.xpoints, 0, npoints); - System.arraycopy(ypoints, 0, this.ypoints, 0, npoints); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(xpoints, 0, this.xpoints, 0, npoints); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(ypoints, 0, this.ypoints, 0, npoints); } /** @@ -235,11 +235,11 @@ public class Polygon implements Shape, Serializable { int[] tmp; tmp = new int[xpoints.length + BUFFER_CAPACITY]; - System.arraycopy(xpoints, 0, tmp, 0, xpoints.length); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(xpoints, 0, tmp, 0, xpoints.length); xpoints = tmp; tmp = new int[ypoints.length + BUFFER_CAPACITY]; - System.arraycopy(ypoints, 0, tmp, 0, ypoints.length); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(ypoints, 0, tmp, 0, ypoints.length); ypoints = tmp; } diff --git a/app/src/main/java/java/awt/TextArea.java b/app/src/main/java/java/awt/TextArea.java new file mode 100644 index 000000000..1c9b4b41a --- /dev/null +++ b/app/src/main/java/java/awt/TextArea.java @@ -0,0 +1,692 @@ +/* + * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package java.awt; + +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.peer.TextAreaPeer; +import java.io.ObjectOutputStream; +import java.io.ObjectInputStream; +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; +import javax.accessibility.*; + +/** + * A TextArea object is a multi-line region + * that displays text. It can be set to allow editing or + * to be read-only. + *

+ * The following image shows the appearance of a text area: + *

+ * A TextArea showing the word 'Hello!' + *

+ * This text area could be created by the following line of code: + * + *


+ * new TextArea("Hello", 5, 40);
+ * 

+ *

+ * @author Sami Shaio + * @since JDK1.0 + */ +public class TextArea extends TextComponent { + + /** + * The number of rows in the TextArea. + * This parameter will determine the text area's height. + * Guaranteed to be non-negative. + * + * @serial + * @see #getRows() + * @see #setRows(int) + */ + int rows; + + /** + * The number of columns in the TextArea. + * A column is an approximate average character + * width that is platform-dependent. + * This parameter will determine the text area's width. + * Guaranteed to be non-negative. + * + * @serial + * @see #setColumns(int) + * @see #getColumns() + */ + int columns; + + private static final String base = "text"; + private static int nameCounter = 0; + + /** + * Create and display both vertical and horizontal scrollbars. + * @since JDK1.1 + */ + public static final int SCROLLBARS_BOTH = 0; + + /** + * Create and display vertical scrollbar only. + * @since JDK1.1 + */ + public static final int SCROLLBARS_VERTICAL_ONLY = 1; + + /** + * Create and display horizontal scrollbar only. + * @since JDK1.1 + */ + public static final int SCROLLBARS_HORIZONTAL_ONLY = 2; + + /** + * Do not create or display any scrollbars for the text area. + * @since JDK1.1 + */ + public static final int SCROLLBARS_NONE = 3; + + /** + * Determines which scrollbars are created for the + * text area. It can be one of four values : + * SCROLLBARS_BOTH = both scrollbars.
+ * SCROLLBARS_HORIZONTAL_ONLY = Horizontal bar only.
+ * SCROLLBARS_VERTICAL_ONLY = Vertical bar only.
+ * SCROLLBARS_NONE = No scrollbars.
+ * + * @serial + * @see #getScrollbarVisibility() + */ + private int scrollbarVisibility; + + /** + * Cache the Sets of forward and backward traversal keys so we need not + * look them up each time. + */ + private static Set forwardTraversalKeys, backwardTraversalKeys; + + /* + * JDK 1.1 serialVersionUID + */ + private static final long serialVersionUID = 3692302836626095722L; + + /** + * Initialize JNI field and method ids + */ + // private static native void initIDs(); + + static { + /* ensure that the necessary native libraries are loaded */ + /* + forwardTraversalKeys = KeyboardFocusManager.initFocusTraversalKeysSet( + "ctrl TAB", + new HashSet()); + backwardTraversalKeys = KeyboardFocusManager.initFocusTraversalKeysSet( + "ctrl shift TAB", + new HashSet()); + */ + } + + /** + * Constructs a new text area with the empty string as text. + * This text area is created with scrollbar visibility equal to + * {@link #SCROLLBARS_BOTH}, so both vertical and horizontal + * scrollbars will be visible for this text area. + * @exception HeadlessException if + * GraphicsEnvironment.isHeadless returns true + * @see java.awt.GraphicsEnvironment#isHeadless() + */ + public TextArea() throws HeadlessException { + this("", 0, 0, SCROLLBARS_BOTH); + } + + /** + * Constructs a new text area with the specified text. + * This text area is created with scrollbar visibility equal to + * {@link #SCROLLBARS_BOTH}, so both vertical and horizontal + * scrollbars will be visible for this text area. + * @param text the text to be displayed; if + * text is null, the empty + * string "" will be displayed + * @exception HeadlessException if + * GraphicsEnvironment.isHeadless returns true + * @see java.awt.GraphicsEnvironment#isHeadless() + */ + public TextArea(String text) throws HeadlessException { + this(text, 0, 0, SCROLLBARS_BOTH); + } + + /** + * Constructs a new text area with the specified number of + * rows and columns and the empty string as text. + * A column is an approximate average character + * width that is platform-dependent. The text area is created with + * scrollbar visibility equal to {@link #SCROLLBARS_BOTH}, so both + * vertical and horizontal scrollbars will be visible for this + * text area. + * @param rows the number of rows + * @param columns the number of columns + * @exception HeadlessException if + * GraphicsEnvironment.isHeadless returns true + * @see java.awt.GraphicsEnvironment#isHeadless() + */ + public TextArea(int rows, int columns) throws HeadlessException { + this("", rows, columns, SCROLLBARS_BOTH); + } + + /** + * Constructs a new text area with the specified text, + * and with the specified number of rows and columns. + * A column is an approximate average character + * width that is platform-dependent. The text area is created with + * scrollbar visibility equal to {@link #SCROLLBARS_BOTH}, so both + * vertical and horizontal scrollbars will be visible for this + * text area. + * @param text the text to be displayed; if + * text is null, the empty + * string "" will be displayed + * @param rows the number of rows + * @param columns the number of columns + * @exception HeadlessException if + * GraphicsEnvironment.isHeadless returns true + * @see java.awt.GraphicsEnvironment#isHeadless() + */ + public TextArea(String text, int rows, int columns) + throws HeadlessException { + this(text, rows, columns, SCROLLBARS_BOTH); + } + + /** + * Constructs a new text area with the specified text, + * and with the rows, columns, and scroll bar visibility + * as specified. All TextArea constructors defer to + * this one. + *

+ * The TextArea class defines several constants + * that can be supplied as values for the + * scrollbars argument: + *

    + *
  • SCROLLBARS_BOTH, + *
  • SCROLLBARS_VERTICAL_ONLY, + *
  • SCROLLBARS_HORIZONTAL_ONLY, + *
  • SCROLLBARS_NONE. + *
+ * Any other value for the + * scrollbars argument is invalid and will result in + * this text area being created with scrollbar visibility equal to + * the default value of {@link #SCROLLBARS_BOTH}. + * @param text the text to be displayed; if + * text is null, the empty + * string "" will be displayed + * @param rows the number of rows; if + * rows is less than 0, + * rows is set to 0 + * @param columns the number of columns; if + * columns is less than 0, + * columns is set to 0 + * @param scrollbars a constant that determines what + * scrollbars are created to view the text area + * @since JDK1.1 + * @exception HeadlessException if + * GraphicsEnvironment.isHeadless returns true + * @see java.awt.GraphicsEnvironment#isHeadless() + */ + public TextArea(String text, int rows, int columns, int scrollbars) + throws HeadlessException { + super(text); + + this.rows = (rows >= 0) ? rows : 0; + this.columns = (columns >= 0) ? columns : 0; + + if (scrollbars >= SCROLLBARS_BOTH && scrollbars <= SCROLLBARS_NONE) { + this.scrollbarVisibility = scrollbars; + } else { + this.scrollbarVisibility = SCROLLBARS_BOTH; + } + /* + setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, + forwardTraversalKeys); + setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, + backwardTraversalKeys); + */ + } + + /** + * Construct a name for this component. Called by getName + * when the name is null. + */ + String constructComponentName() { + synchronized (TextArea.class) { + return base + nameCounter++; + } + } + + /** + * Creates the TextArea's peer. The peer allows us to modify + * the appearance of the TextArea without changing any of its + * functionality. + */ + public void addNotify() { + /* + synchronized (getTreeLock()) { + if (peer == null) + peer = getToolkit().createTextArea(this); + super.addNotify(); + } + */ + } + + /** + * Inserts the specified text at the specified position + * in this text area. + *

Note that passing null or inconsistent + * parameters is invalid and will result in unspecified + * behavior. + * + * @param str the non-null text to insert + * @param pos the position at which to insert + * @see java.awt.TextComponent#setText + * @see java.awt.TextArea#replaceRange + * @see java.awt.TextArea#append + * @since JDK1.1 + */ + public void insert(String str, int pos) { + insertText(str, pos); + } + + /** + * @deprecated As of JDK version 1.1, + * replaced by insert(String, int). + */ + @Deprecated + public synchronized void insertText(String str, int pos) { + /* + TextAreaPeer peer = (TextAreaPeer)this.peer; + if (peer != null) { + peer.insert(str, pos); + } + */ + text = text.substring(0, pos) + str + text.substring(pos); + } + + /** + * Appends the given text to the text area's current text. + *

Note that passing null or inconsistent + * parameters is invalid and will result in unspecified + * behavior. + * + * @param str the non-null text to append + * @see java.awt.TextArea#insert + * @since JDK1.1 + */ + public void append(String str) { + appendText(str); + } + + /** + * @deprecated As of JDK version 1.1, + * replaced by append(String). + */ + @Deprecated + public synchronized void appendText(String str) { + insertText(str, getText().length()); + } + + /** + * Replaces text between the indicated start and end positions + * with the specified replacement text. The text at the end + * position will not be replaced. The text at the start + * position will be replaced (unless the start position is the + * same as the end position). + * The text position is zero-based. The inserted substring may be + * of a different length than the text it replaces. + *

Note that passing null or inconsistent + * parameters is invalid and will result in unspecified + * behavior. + * + * @param str the non-null text to use as + * the replacement + * @param start the start position + * @param end the end position + * @see java.awt.TextArea#insert + * @since JDK1.1 + */ + public void replaceRange(String str, int start, int end) { + replaceText(str, start, end); + } + + /** + * @deprecated As of JDK version 1.1, + * replaced by replaceRange(String, int, int). + */ + @Deprecated + public synchronized void replaceText(String str, int start, int end) { + /* + TextAreaPeer peer = (TextAreaPeer)this.peer; + if (peer != null) { + peer.replaceRange(str, start, end); + } + */ + text = text.substring(0, start) + str + text.substring(end); + } + + /** + * Returns the number of rows in the text area. + * @return the number of rows in the text area + * @see #setRows(int) + * @see #getColumns() + * @since JDK1 + */ + public int getRows() { + return rows; + } + + /** + * Sets the number of rows for this text area. + * @param rows the number of rows + * @see #getRows() + * @see #setColumns(int) + * @exception IllegalArgumentException if the value + * supplied for rows + * is less than 0 + * @since JDK1.1 + */ + public void setRows(int rows) { + int oldVal = this.rows; + if (rows < 0) { + throw new IllegalArgumentException("rows less than zero."); + } + if (rows != oldVal) { + this.rows = rows; + invalidate(); + } + } + + /** + * Returns the number of columns in this text area. + * @return the number of columns in the text area + * @see #setColumns(int) + * @see #getRows() + */ + public int getColumns() { + return columns; + } + + /** + * Sets the number of columns for this text area. + * @param columns the number of columns + * @see #getColumns() + * @see #setRows(int) + * @exception IllegalArgumentException if the value + * supplied for columns + * is less than 0 + * @since JDK1.1 + */ + public void setColumns(int columns) { + int oldVal = this.columns; + if (columns < 0) { + throw new IllegalArgumentException("columns less than zero."); + } + if (columns != oldVal) { + this.columns = columns; + invalidate(); + } + } + + /** + * Returns an enumerated value that indicates which scroll bars + * the text area uses. + *

+ * The TextArea class defines four integer constants + * that are used to specify which scroll bars are available. + * TextArea has one constructor that gives the + * application discretion over scroll bars. + * + * @return an integer that indicates which scroll bars are used + * @see java.awt.TextArea#SCROLLBARS_BOTH + * @see java.awt.TextArea#SCROLLBARS_VERTICAL_ONLY + * @see java.awt.TextArea#SCROLLBARS_HORIZONTAL_ONLY + * @see java.awt.TextArea#SCROLLBARS_NONE + * @see java.awt.TextArea#TextArea(java.lang.String, int, int, int) + * @since JDK1.1 + */ + public int getScrollbarVisibility() { + return scrollbarVisibility; + } + + + /** + * Determines the preferred size of a text area with the specified + * number of rows and columns. + * @param rows the number of rows + * @param columns the number of columns + * @return the preferred dimensions required to display + * the text area with the specified + * number of rows and columns + * @see java.awt.Component#getPreferredSize + * @since JDK1.1 + */ + public Dimension getPreferredSize(int rows, int columns) { + return preferredSize(rows, columns); + } + + /** + * @deprecated As of JDK version 1.1, + * replaced by getPreferredSize(int, int). + */ + @Deprecated + public Dimension preferredSize(int rows, int columns) { + synchronized (getTreeLock()) { + // TextAreaPeer peer = (TextAreaPeer)this.peer; + return /* (peer != null) ? + peer.getPreferredSize(rows, columns) : */ + super.preferredSize(); + } + } + + /** + * Determines the preferred size of this text area. + * @return the preferred dimensions needed for this text area + * @see java.awt.Component#getPreferredSize + * @since JDK1.1 + */ + public Dimension getPreferredSize() { + return preferredSize(); + } + + /** + * @deprecated As of JDK version 1.1, + * replaced by getPreferredSize(). + */ + @Deprecated + public Dimension preferredSize() { + synchronized (getTreeLock()) { + return ((rows > 0) && (columns > 0)) ? + preferredSize(rows, columns) : + super.preferredSize(); + } + } + + /** + * Determines the minimum size of a text area with the specified + * number of rows and columns. + * @param rows the number of rows + * @param columns the number of columns + * @return the minimum dimensions required to display + * the text area with the specified + * number of rows and columns + * @see java.awt.Component#getMinimumSize + * @since JDK1.1 + */ + public Dimension getMinimumSize(int rows, int columns) { + return minimumSize(rows, columns); + } + + /** + * @deprecated As of JDK version 1.1, + * replaced by getMinimumSize(int, int). + */ + @Deprecated + public Dimension minimumSize(int rows, int columns) { + synchronized (getTreeLock()) { + /* + TextAreaPeer peer = (TextAreaPeer)this.peer; + return (peer != null) ? + peer.getMinimumSize(rows, columns) : + super.minimumSize(); + */ + + return super.minimumSize(); + } + } + + /** + * Determines the minimum size of this text area. + * @return the preferred dimensions needed for this text area + * @see java.awt.Component#getPreferredSize + * @since JDK1.1 + */ + public Dimension getMinimumSize() { + return minimumSize(); + } + + /** + * @deprecated As of JDK version 1.1, + * replaced by getMinimumSize(). + */ + @Deprecated + public Dimension minimumSize() { + synchronized (getTreeLock()) { + return ((rows > 0) && (columns > 0)) ? + minimumSize(rows, columns) : + super.minimumSize(); + } + } + + /** + * Returns a string representing the state of this TextArea. + * This method is intended to be used only for debugging purposes, and the + * content and format of the returned string may vary between + * implementations. The returned string may be empty but may not be + * null. + * + * @return the parameter string of this text area + */ + protected String paramString() { + String sbVisStr; + switch (scrollbarVisibility) { + case SCROLLBARS_BOTH: + sbVisStr = "both"; + break; + case SCROLLBARS_VERTICAL_ONLY: + sbVisStr = "vertical-only"; + break; + case SCROLLBARS_HORIZONTAL_ONLY: + sbVisStr = "horizontal-only"; + break; + case SCROLLBARS_NONE: + sbVisStr = "none"; + break; + default: + sbVisStr = "invalid display policy"; + } + + return super.paramString() + ",rows=" + rows + + ",columns=" + columns + + ",scrollbarVisibility=" + sbVisStr; + } + + + /* + * Serialization support. + */ + /** + * The textArea Serialized Data Version. + * + * @serial + */ + private int textAreaSerializedDataVersion = 2; + + /** + * Read the ObjectInputStream. + * @exception HeadlessException if + * GraphicsEnvironment.isHeadless() returns + * true + * @see java.awt.GraphicsEnvironment#isHeadless + */ + private void readObject(ObjectInputStream s) + throws ClassNotFoundException, IOException, HeadlessException + { + // HeadlessException will be thrown by TextComponent's readObject + s.defaultReadObject(); + + // Make sure the state we just read in for columns, rows, + // and scrollbarVisibility has legal values + if (columns < 0) { + columns = 0; + } + if (rows < 0) { + rows = 0; + } + + if ((scrollbarVisibility < SCROLLBARS_BOTH) || + (scrollbarVisibility > SCROLLBARS_NONE)) { + this.scrollbarVisibility = SCROLLBARS_BOTH; + } + + /* + if (textAreaSerializedDataVersion < 2) { + setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, + forwardTraversalKeys); + setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, + backwardTraversalKeys); + } + */ + } + + +///////////////// +// Accessibility support +//////////////// + + + /** + * Returns the AccessibleContext associated with + * this TextArea. For text areas, the + * AccessibleContext takes the form of an + * AccessibleAWTTextArea. + * A new AccessibleAWTTextArea instance is created if necessary. + * + * @return an AccessibleAWTTextArea that serves as the + * AccessibleContext of this TextArea + * @since 1.3 + */ +/* + public AccessibleContext getAccessibleContext() { + if (accessibleContext == null) { + accessibleContext = new AccessibleAWTTextArea(); + } + return accessibleContext; + } +*/ +} diff --git a/app/src/main/java/java/awt/TextComponent.java b/app/src/main/java/java/awt/TextComponent.java new file mode 100644 index 000000000..1633255c1 --- /dev/null +++ b/app/src/main/java/java/awt/TextComponent.java @@ -0,0 +1,21 @@ +package java.awt; + +public class TextComponent extends Component +{ + public String text; + public TextComponent() { + this(""); + } + + public TextComponent(String text) { + this.text = text; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } +} diff --git a/app/src/main/java/java/awt/Toolkit.java b/app/src/main/java/java/awt/Toolkit.java index 79cb9f7de..fede13fbd 100644 --- a/app/src/main/java/java/awt/Toolkit.java +++ b/app/src/main/java/java/awt/Toolkit.java @@ -1,57 +1,1455 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package java.awt; +import java.awt.event.AWTEventListener; +import java.awt.event.AWTEventListenerProxy; +import java.awt.event.InputEvent; +import java.awt.im.InputMethodHighlight; +import java.awt.image.ColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.peer.FontPeer; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; + +import java.lang.reflect.InvocationTargetException; +import java.net.URL; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Collections; +import java.util.EventListener; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.MissingResourceException; +import java.util.Properties; +import java.util.ResourceBundle; + +import org.apache.harmony.awt.ChoiceStyle; +import org.apache.harmony.awt.ComponentInternals; +import org.apache.harmony.awt.ContextStorage; +import org.apache.harmony.awt.ReadOnlyIterator; +import org.apache.harmony.awt.internal.nls.Messages; +import org.apache.harmony.awt.wtk.CreationParams; +import org.apache.harmony.awt.wtk.GraphicsFactory; +import org.apache.harmony.awt.wtk.NativeCursor; + +import org.apache.harmony.awt.wtk.NativeEventQueue; +import org.apache.harmony.awt.wtk.NativeEventThread; +import org.apache.harmony.awt.wtk.ShutdownWatchdog; +import org.apache.harmony.awt.wtk.Synchronizer; +import org.apache.harmony.awt.wtk.WTK; +import org.apache.harmony.luni.util.NotImplementedException; import java.awt.datatransfer.*; -import java.awt.peer.*; -import javax.imageio.*; -import java.io.*; -public class Toolkit extends Object -{ - private static Toolkit toolkit = new Toolkit(); - private DesktopPeer desktopPeer = new DesktopPeer(){}; - private Clipboard clipboard = new Clipboard(); +/** + * The Toolkit class is the representation of the platform-specific Abstract + * Window Toolkit implementation. Toolkit's subclasses are used to bind the + * various components to particular native toolkit implementations. + * + * @since Android 1.0 + */ +public abstract class Toolkit { - public Image createImage(String fileStr) - { - try { - return ImageIO.read(new File(fileStr)); - } catch (IOException e) { - e.printStackTrace(); - return null; - } - } + /** + * The Constant RECOURCE_PATH. + */ + private static final String RECOURCE_PATH = "org.apache.harmony.awt.resources.AWTProperties"; //$NON-NLS-1$ - public static void checkHeadless() - { - GraphicsEnvironment.checkHeadless(); - } + /** + * The Constant properties. + */ + private static final ResourceBundle properties = loadResources(RECOURCE_PATH); - public boolean isAlwaysOnTopSupported() - { - // Android implementation: NOT SUPPORTED + /** + * The dispatcher. + */ + Dispatcher dispatcher; + + /** + * The system event queue core. + */ + private EventQueueCore systemEventQueueCore; + + /** + * The dispatch thread. + */ + EventDispatchThread dispatchThread; + + /** + * The native thread. + */ + NativeEventThread nativeThread; + + /** + * The AWT events manager. + */ + protected AWTEventsManager awtEventsManager; + + /** + * The Class AWTTreeLock. + */ + private class AWTTreeLock { + } + + /** + * The AWT tree lock. + */ + final Object awtTreeLock = new AWTTreeLock(); + + /** + * The synchronizer. + */ + private final Synchronizer synchronizer = ContextStorage.getSynchronizer(); + + /** + * The shutdown watchdog. + */ + final ShutdownWatchdog shutdownWatchdog = new ShutdownWatchdog(); + + /** + * The auto number. + */ + final AutoNumber autoNumber = new AutoNumber(); + + /** + * The event type lookup. + */ + final AWTEvent.EventTypeLookup eventTypeLookup = new AWTEvent.EventTypeLookup(); + + /** + * The b dynamic layout set. + */ + private boolean bDynamicLayoutSet = true; + + /** + * The set of desktop properties that user set directly. + */ + private final HashSet userPropSet = new HashSet(); + + /** + * The desktop properties. + */ + protected Map desktopProperties; + + /** + * The desktop props support. + */ + protected PropertyChangeSupport desktopPropsSupport; + + /** + * For this component the native window is being created It is used in the + * callback-driven window creation (e.g. on Windows in the handler of + * WM_CREATE event) to establish the connection between this component and + * its native window. + */ + private Object recentNativeWindowComponent; + + /** + * The wtk. + */ + private WTK wtk; + + /** + * The Class ComponentInternalsImpl. + * + * @since Android 1.0 + */ + protected final class ComponentInternalsImpl extends ComponentInternals { + + /** + * Shutdown. + */ + @Override + public void shutdown() { + dispatchThread.shutdown(); + } + + /** + * Sets the desktop property to the specified value and fires a property + * change event. + * + * @param name + * the name of property. + * @param value + * the new value of property. + */ + @Override + public void setDesktopProperty(String name, Object value) { + Toolkit.this.setDesktopProperty(name, value); + } + } + + /** + * A lot of methods must throw HeadlessException if + * GraphicsEnvironment.isHeadless() returns true. + * + * @throws HeadlessException + * the headless exception. + */ + static void checkHeadless() throws HeadlessException { + if (GraphicsEnvironment.getLocalGraphicsEnvironment().isHeadlessInstance()) + throw new HeadlessException(); + } + + /** + * Lock AWT. + */ + final void lockAWT() { + synchronizer.lock(); + } + + /** + * Static lock AWT. + */ + static final void staticLockAWT() { + ContextStorage.getSynchronizer().lock(); + } + + /** + * Unlock AWT. + */ + final void unlockAWT() { + synchronizer.unlock(); + } + + /** + * Static unlock AWT. + */ + static final void staticUnlockAWT() { + ContextStorage.getSynchronizer().unlock(); + } + + /** + * InvokeAndWait under AWT lock. W/o this method system can hang up. Added + * to support modality (Dialog.show() & PopupMenu.show()) from not event + * dispatch thread. Use in other cases is not recommended. Still can be + * called only for whole API methods that cannot be called from other + * classes API methods. Examples: show() for modal dialogs - correct, only + * user can call it, directly or through setVisible(true) setBounds() for + * components - incorrect, setBounds() can be called from layoutContainer() + * for layout managers + * + * @param runnable + * the runnable. + * @throws InterruptedException + * the interrupted exception. + * @throws InvocationTargetException + * the invocation target exception. + */ + final void unsafeInvokeAndWait(Runnable runnable) throws InterruptedException, + InvocationTargetException { + synchronizer.storeStateAndFree(); + try { + EventQueue.invokeAndWait(runnable); + } finally { + synchronizer.lockAndRestoreState(); + } + } + + /** + * Gets the synchronizer. + * + * @return the synchronizer. + */ + final Synchronizer getSynchronizer() { + return synchronizer; + } + + /** + * Gets the wTK. + * + * @return the wTK. + */ + final WTK getWTK() { + return wtk; + } + + /** + * Gets the property with the specified key and default value. This method + * returns the defValue if the property is not found. + * + * @param propName + * the name of property. + * @param defVal + * the default value. + * @return the property value. + */ + public static String getProperty(String propName, String defVal) { + if (propName == null) { + // awt.7D=Property name is null + throw new NullPointerException(Messages.getString("awt.7D")); //$NON-NLS-1$ + } + staticLockAWT(); + try { + String retVal = null; + if (properties != null) { + try { + retVal = properties.getString(propName); + } catch (MissingResourceException e) { + } catch (ClassCastException e) { + } + } + return (retVal == null) ? defVal : retVal; + } finally { + staticUnlockAWT(); + } + } + + /** + * Gets the default Toolkit. + * + * @return the default Toolkit. + */ + public static Toolkit getDefaultToolkit() { + synchronized (ContextStorage.getContextLock()) { + if (ContextStorage.shutdownPending()) { + return null; + } + Toolkit defToolkit = ContextStorage.getDefaultToolkit(); + if (defToolkit != null) { + return defToolkit; + } + staticLockAWT(); + try { + defToolkit = GraphicsEnvironment.isHeadless() ? new HeadlessToolkit() + : new ToolkitImpl(); + ContextStorage.setDefaultToolkit(defToolkit); + return defToolkit; + } finally { + staticUnlockAWT(); + } + // TODO: read system property named awt.toolkit + // and create an instance of the specified class, + // by default use ToolkitImpl + } + } + + /** + * Gets the default Font. + * + * @return the default Font for Toolkit. + */ + Font getDefaultFont() { + return wtk.getSystemProperties().getDefaultFont(); + } + + /** + * Load resources. + * + * @param path + * the path. + * @return the resource bundle. + */ + private static ResourceBundle loadResources(String path) { + try { + return ResourceBundle.getBundle(path); + } catch (MissingResourceException e) { + return null; + } + } + + /** + * Gets the wTK class name. + * + * @return the wTK class name. + */ + private static String getWTKClassName() { + return "com.android.internal.awt.AndroidWTK"; + } + + /** + * Gets the component by id. + * + * @param id + * the id. + * @return the component by id. + */ + Component getComponentById(long id) { + if (id == 0) { + return null; + } + return null; + } + + /** + * Gets the GraphicsFactory. + * + * @return the GraphicsFactory object. + */ + public GraphicsFactory getGraphicsFactory() { + return wtk.getGraphicsFactory(); + } + + /** + * Instantiates a new toolkit. + */ + public Toolkit() { + init(); + } + + /** + * Initiates AWT. + */ + protected void init() { + lockAWT(); + try { + ComponentInternals.setComponentInternals(new ComponentInternalsImpl()); + new EventQueue(this); // create the system EventQueue + dispatcher = new Dispatcher(this); + final String className = getWTKClassName(); + desktopProperties = new HashMap(); + desktopPropsSupport = new PropertyChangeSupport(this); + awtEventsManager = new AWTEventsManager(); + dispatchThread = new EventDispatchThread(this, dispatcher); + nativeThread = new NativeEventThread(); + NativeEventThread.Init init = new NativeEventThread.Init() { + public WTK init() { + wtk = createWTK(className); + wtk.getNativeEventQueue().setShutdownWatchdog(shutdownWatchdog); + synchronizer.setEnvironment(wtk, dispatchThread); + ContextStorage.setWTK(wtk); + return wtk; + } + }; + nativeThread.start(init); + dispatchThread.start(); + wtk.getNativeEventQueue().awake(); + } finally { + unlockAWT(); + } + } + + public boolean isAlwaysOnTopSupported() { return false; } - private class AWTTreeLock { + /** + * Synchronizes this toolkit's graphics. + */ + public abstract void sync(); + + /** + * Returns the construction status of a specified image that is being + * created. + * + * @param a0 + * the image to be checked. + * @param a1 + * the width of scaled image for which the status is being + * checked or -1. + * @param a2 + * the height of scaled image for which the status is being + * checked or -1. + * @param a3 + * the ImageObserver object to be notified while the image is + * being prepared. + * @return the ImageObserver flags which give the current state of the image + * data. + */ + public abstract int checkImage(Image a0, int a1, int a2, ImageObserver a3); + + /** + * Creates the image with the specified ImageProducer. + * + * @param a0 + * the ImageProducer to be used for image creation. + * @return the image with the specified ImageProducer. + */ + public abstract Image createImage(ImageProducer a0); + + /** + * Creates the image from the specified byte array, offset and length. The + * byte array should contain data with image format supported by Toolkit + * such as JPEG, GIF, or PNG. + * + * @param a0 + * the byte array with the image data. + * @param a1 + * the offset of the beginning the image data in the byte array. + * @param a2 + * the length of the image data in the byte array. + * @return the created Image. + */ + public abstract Image createImage(byte[] a0, int a1, int a2); + + /** + * Creates the image using image data from the specified URL. + * + * @param a0 + * the URL for extracting image data. + * @return the Image. + */ + public abstract Image createImage(URL a0); + + /** + * Creates the image using image data from the specified file. + * + * @param a0 + * the file name which contains image data of supported format. + * @return the Image. + */ + public abstract Image createImage(String a0); + + /** + * Gets the default clipboard. + * @return the FontMetrics for the specified Font. + */ + public abstract Clipboard getSystemClipboard(); + + /** + * Gets the color model. + * + * @return the ColorModel of Toolkit's screen. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. + */ + public abstract ColorModel getColorModel() throws HeadlessException; + + /** + * Gets the screen device metrics for the specified font. + * + * @param font + * the Font. + * @return the FontMetrics for the specified Font. + * @deprecated Use getLineMetrics method from Font class. + */ + + @Deprecated + public abstract FontMetrics getFontMetrics(Font font); + + /** + * Prepares the specified image for rendering on the screen with the + * specified size. + * + * @param a0 + * the Image to be prepared. + * @param a1 + * the width of the screen representation or -1 for the current + * screen. + * @param a2 + * the height of the screen representation or -1 for the current + * screen. + * @param a3 + * the ImageObserver object to be notified as soon as the image + * is prepared. + * @return true, if image is fully prepared, false otherwise. + */ + public abstract boolean prepareImage(Image a0, int a1, int a2, ImageObserver a3); + + /** + * Creates an audio beep. + */ + public abstract void beep(); + + /** + * Returns the array of font names which are available in this Toolkit. + * + * @return the array of font names which are available in this Toolkit. + * @deprecated use GraphicsEnvironment.getAvailableFontFamilyNames() method. + */ + @Deprecated + public abstract String[] getFontList(); + + /** + * Gets the the Font implementation using the specified peer interface. + * + * @param a0 + * the Font name to be implemented. + * @param a1 + * the the font style: PLAIN, BOLD, ITALIC. + * @return the FontPeer implementation of the specified Font. + * @deprecated use java.awt.GraphicsEnvironment.getAllFonts method. + */ + + @Deprecated + protected abstract FontPeer getFontPeer(String a0, int a1); + + /** + * Gets the image from the specified file which contains image data in a + * supported image format (such as JPEG, GIF, or PNG); this method should + * return the same Image for multiple calls of this method with the same + * image file name. + * + * @param a0 + * the file name which contains image data in a supported image + * format (such as JPEG, GIF, or PNG). + * @return the Image. + */ + public abstract Image getImage(String a0); + + /** + * Gets the image from the specified URL which contains image data in a + * supported image format (such as JPEG, GIF, or PNG); this method should + * return the same Image for multiple calls of this method with the same + * image URL. + * + * @param a0 + * the URL which contains image data in a supported image format + * (such as JPEG, GIF, or PNG). + * @return the Image. + */ + public abstract Image getImage(URL a0); + + /** + * Gets the screen resolution. + * + * @return the screen resolution. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. + */ + public abstract int getScreenResolution() throws HeadlessException; + + /** + * Gets the screen size. + * + * @return a Dimension object containing the width and height of the screen. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. + */ + public abstract Dimension getScreenSize() throws HeadlessException; + + /** + * Gets the EventQueue instance without checking access. + * + * @return the system EventQueue. + */ + protected abstract EventQueue getSystemEventQueueImpl(); + + /** + * Returns a map of text attributes for the abstract level description of + * the specified input method highlight, or null if no mapping is found. + * + * @param highlight + * the InputMethodHighlight. + * @return the Map. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. + */ + public abstract Map mapInputMethodHighlight( + InputMethodHighlight highlight) throws HeadlessException; + + /** + * Map input method highlight impl. + * + * @param highlight + * the highlight. + * @return the map. + * @throws HeadlessException + * the headless exception. + */ + Map mapInputMethodHighlightImpl(InputMethodHighlight highlight) + throws HeadlessException { + HashMap map = new HashMap(); + wtk.getSystemProperties().mapInputMethodHighlight(highlight, map); + return Collections. unmodifiableMap(map); } - final Object awtTreeLock = new AWTTreeLock(); - - private Toolkit() - {} + /** + * Adds the specified PropertyChangeListener listener for the specified + * property. + * + * @param propName + * the property name for which the specified + * PropertyChangeListener will be added. + * @param l + * the PropertyChangeListener object. + */ + public void addPropertyChangeListener(String propName, PropertyChangeListener l) { + lockAWT(); + try { + if (desktopProperties.isEmpty()) { + initializeDesktopProperties(); + } + } finally { + unlockAWT(); + } + if (l != null) { // there is no guarantee that null listener will not be + // added + desktopPropsSupport.addPropertyChangeListener(propName, l); + } + } + + /** + * Returns an array of the property change listeners registered with this + * Toolkit. + * + * @return an array of the property change listeners registered with this + * Toolkit. + */ + public PropertyChangeListener[] getPropertyChangeListeners() { + return desktopPropsSupport.getPropertyChangeListeners(); + } + + /** + * Returns an array of the property change listeners registered with this + * Toolkit for notification regarding the specified property. + * + * @param propName + * the property name for which the PropertyChangeListener was + * registered. + * @return the array of PropertyChangeListeners registered for the specified + * property name. + */ + public PropertyChangeListener[] getPropertyChangeListeners(String propName) { + return desktopPropsSupport.getPropertyChangeListeners(propName); + } + + /** + * Removes the specified property change listener registered for the + * specified property name. + * + * @param propName + * the property name. + * @param l + * the PropertyChangeListener registered for the specified + * property name. + */ + public void removePropertyChangeListener(String propName, PropertyChangeListener l) { + desktopPropsSupport.removePropertyChangeListener(propName, l); + } + + /** + * Creates a custom cursor with the specified Image, hot spot, and cursor + * description. + * + * @param img + * the image of activated cursor. + * @param hotSpot + * the Point giving the coordinates of the cursor's hot spot. + * @param name + * the cursor description. + * @return the cursor with the specified Image, hot spot, and cursor + * description. + * @throws IndexOutOfBoundsException + * if the hot spot values are outside the bounds of the cursor. + * @throws HeadlessException + * if isHeadless() method of GraphicsEnvironment class returns + * true. + */ + public Cursor createCustomCursor(Image img, Point hotSpot, String name) + throws IndexOutOfBoundsException, HeadlessException { + lockAWT(); + try { + int w = img.getWidth(null), x = hotSpot.x; + int h = img.getHeight(null), y = hotSpot.y; + if (x < 0 || x >= w || y < 0 || y >= h) { + // awt.7E=invalid hotSpot + throw new IndexOutOfBoundsException(Messages.getString("awt.7E")); //$NON-NLS-1$ + } + return new Cursor(name, img, hotSpot); + } finally { + unlockAWT(); + } + } + + /** + * Returns the supported cursor dimension which is closest to the specified + * width and height. If the Toolkit only supports a single cursor size, this + * method should return the supported cursor size. If custom cursor is not + * supported, a dimension of 0, 0 should be returned. + * + * @param prefWidth + * the preferred cursor width. + * @param prefHeight + * the preferred cursor height. + * @return the supported cursor dimension which is closest to the specified + * width and height. + * @throws HeadlessException + * if GraphicsEnvironment.isHeadless() returns true. + */ + public Dimension getBestCursorSize(int prefWidth, int prefHeight) throws HeadlessException { + lockAWT(); + try { + return wtk.getCursorFactory().getBestCursorSize(prefWidth, prefHeight); + } finally { + unlockAWT(); + } + } + + /** + * Gets the value for the specified desktop property. + * + * @param propName + * the property name. + * @return the Object that is the property's value. + */ + public final Object getDesktopProperty(String propName) { + lockAWT(); + try { + if (desktopProperties.isEmpty()) { + initializeDesktopProperties(); + } + if (propName.equals("awt.dynamicLayoutSupported")) { //$NON-NLS-1$ + // dynamicLayoutSupported is special case + return Boolean.valueOf(isDynamicLayoutActive()); + } + Object val = desktopProperties.get(propName); + if (val == null) { + // try to lazily load prop value + // just for compatibility, our lazilyLoad is empty + val = lazilyLoadDesktopProperty(propName); + } + return val; + } finally { + unlockAWT(); + } + } + + /** + * Returns the locking key state for the specified key. + * + * @param a0 + * the key code: VK_CAPS_LOCK, VK_NUM_LOCK, VK_SCROLL_LOCK, or + * VK_KANA_LOCK. + * @return true if the specified key code is in the locked state, false + * otherwise. + * @throws UnsupportedOperationException + * if the state of this key can't be retrieved, or if the + * keyboard doesn't have this key. + * @throws NotImplementedException + * if this method is not implemented. + */ + public boolean getLockingKeyState(int a0) throws UnsupportedOperationException, + org.apache.harmony.luni.util.NotImplementedException { + lockAWT(); + try { + } finally { + unlockAWT(); + } + if (true) { + throw new RuntimeException("Method is not implemented"); //TODO: implement //$NON-NLS-1$ + } + return true; + } + + /** + * Returns the maximum number of colors which the Toolkit supports for + * custom cursor. + * + * @return the maximum cursor colors. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. + */ + public int getMaximumCursorColors() throws HeadlessException { + lockAWT(); + try { + return wtk.getCursorFactory().getMaximumCursorColors(); + } finally { + unlockAWT(); + } + } + + /** + * Gets the menu shortcut key mask. + * + * @return the menu shortcut key mask. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. + */ + public int getMenuShortcutKeyMask() throws HeadlessException { + lockAWT(); + try { + return InputEvent.CTRL_MASK; + } finally { + unlockAWT(); + } + } + + /** + * Gets the screen insets. + * + * @param gc + * the GraphicsConfiguration. + * @return the insets of this toolkit. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. + */ + public Insets getScreenInsets(GraphicsConfiguration gc) throws HeadlessException { + if (gc == null) { + throw new NullPointerException(); + } + lockAWT(); + try { + return new Insets(0, 0, 0, 0); // TODO: get real screen insets + } finally { + unlockAWT(); + } + } + + /** + * Gets the system EventQueue instance. If the default implementation of + * checkAwtEventQueueAccess is used, then this results of a call to the + * security manager's checkPermission method with an + * AWTPermission("accessEventQueue") permission. + * + * @return the system EventQueue instance. + */ + public final EventQueue getSystemEventQueue() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkAwtEventQueueAccess(); + } + return getSystemEventQueueImpl(); + } + + /** + * Gets the system event queue core. + * + * @return the system event queue core. + */ + EventQueueCore getSystemEventQueueCore() { + return systemEventQueueCore; + } + + /** + * Sets the system event queue core. + * + * @param core + * the new system event queue core. + */ + void setSystemEventQueueCore(EventQueueCore core) { + systemEventQueueCore = core; + } + + /** + * Initialize the desktop properties. + */ + protected void initializeDesktopProperties() { + lockAWT(); + try { + wtk.getSystemProperties().init(desktopProperties); + } finally { + unlockAWT(); + } + } + + /** + * Checks if dynamic layout of Containers is active or not. + * + * @return true, if is dynamic layout of Containers is active, false + * otherwise. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. + */ + public boolean isDynamicLayoutActive() throws HeadlessException { + lockAWT(); + try { + // always return true + return true; + } finally { + unlockAWT(); + } + } + + /** + * Returns if the layout of Containers is checked dynamically during + * resizing, or statically after resizing is completed. + * + * @return true, if if the layout of Containers is checked dynamically + * during resizing; false, if the layout of Containers is checked + * statically after resizing is completed. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. + */ + protected boolean isDynamicLayoutSet() throws HeadlessException { + lockAWT(); + try { + return bDynamicLayoutSet; + } finally { + unlockAWT(); + } + } + + /** + * Checks if the specified frame state is supported by Toolkit or not. + * + * @param state + * the frame state. + * @return true, if frame state is supported, false otherwise. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. + */ + public boolean isFrameStateSupported(int state) throws HeadlessException { + lockAWT(); + try { + return wtk.getWindowFactory().isWindowStateSupported(state); + } finally { + unlockAWT(); + } + } + + /** + * Loads the value of the desktop property with the specified property name. + * + * @param propName + * the property name. + * @return the desktop property values. + */ + protected Object lazilyLoadDesktopProperty(String propName) { + return null; + } + + /** + * Loads the current system color values to the specified array. + * + * @param colors + * the array where the current system color values are written by + * this method. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. + */ + protected void loadSystemColors(int[] colors) throws HeadlessException { + lockAWT(); + try { + } finally { + unlockAWT(); + } + } + + /** + * Sets the value of the desktop property with the specified name. + * + * @param propName + * the property's name. + * @param value + * the property's value. + */ + protected final void setDesktopProperty(String propName, Object value) { + Object oldVal; + lockAWT(); + try { + oldVal = getDesktopProperty(propName); + userPropSet.add(propName); + desktopProperties.put(propName, value); + } finally { + unlockAWT(); + } + desktopPropsSupport.firePropertyChange(propName, oldVal, value); + } + + /** + * Sets the layout state, whether the Container layout is checked + * dynamically during resizing, or statically after resizing is completed. + * + * @param dynamic + * the new dynamic layout state - if true the layout of + * Containers is checked dynamically during resizing, if false - + * statically after resizing is completed. + * @throws HeadlessException + * if the GraphicsEnvironment.isHeadless() method returns true. + */ + public void setDynamicLayout(boolean dynamic) throws HeadlessException { + lockAWT(); + try { + bDynamicLayoutSet = dynamic; + } finally { + unlockAWT(); + } + } + + /** + * Sets the locking key state for the specified key code. + * + * @param a0 + * the key code: VK_CAPS_LOCK, VK_NUM_LOCK, VK_SCROLL_LOCK, or + * VK_KANA_LOCK. + * @param a1 + * the state - true to set the specified key code to the locked + * state, false - to unlock it. + * @throws UnsupportedOperationException + * if the state of this key can't be set, or if the keyboard + * doesn't have this key. + * @throws NotImplementedException + * if this method is not implemented. + */ + public void setLockingKeyState(int a0, boolean a1) throws UnsupportedOperationException, + org.apache.harmony.luni.util.NotImplementedException { + lockAWT(); + try { + } finally { + unlockAWT(); + } + if (true) { + throw new RuntimeException("Method is not implemented"); //TODO: implement //$NON-NLS-1$ + } + return; + } + + /** + * On queue empty. + */ + void onQueueEmpty() { + throw new RuntimeException("Not implemented!"); + } + + /** + * Creates the wtk. + * + * @param clsName + * the cls name. + * @return the wTK. + */ + private WTK createWTK(String clsName) { + WTK newWTK = null; + try { + newWTK = (WTK)Class.forName(clsName).newInstance(); + } catch (Exception e) { + throw new RuntimeException(e); + } + return newWTK; + } + + /** + * Connect the component to its native window + * + * @param winId + * the id of native window just created. + */ + boolean onWindowCreated(long winId) { + return false; + } + + /** + * Gets the native event queue. + * + * @return the native event queue. + */ + NativeEventQueue getNativeEventQueue() { + return wtk.getNativeEventQueue(); + } + + /** + * Returns a shared instance of implementation of + * org.apache.harmony.awt.wtk.NativeCursor for current platform for. + * + * @param type + * the Java Cursor type. + * @return new instance of implementation of NativeCursor. + */ + NativeCursor createNativeCursor(int type) { + return wtk.getCursorFactory().getCursor(type); + } + + /** + * Returns a shared instance of implementation of + * org.apache.harmony.awt.wtk.NativeCursor for current platform for custom + * cursor + * + * @param img + * the img. + * @param hotSpot + * the hot spot. + * @param name + * the name. + * @return new instance of implementation of NativeCursor. + */ + NativeCursor createCustomNativeCursor(Image img, Point hotSpot, String name) { + return wtk.getCursorFactory().createCustomCursor(img, hotSpot.x, hotSpot.y); + } + + /** + * Adds an AWTEventListener to the Toolkit to listen for events of types + * corresponding to bits in the specified event mask. Event masks are + * defined in AWTEvent class. + * + * @param listener + * the AWTEventListener. + * @param eventMask + * the bitmask of event types. + */ + public void addAWTEventListener(AWTEventListener listener, long eventMask) { + lockAWT(); + try { + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkPermission(awtEventsManager.permission); + } + awtEventsManager.addAWTEventListener(listener, eventMask); + } finally { + unlockAWT(); + } + } + + /** + * Removes the specified AWT event listener. + * + * @param listener + * the AWTEventListener to be removed. + */ + public void removeAWTEventListener(AWTEventListener listener) { + lockAWT(); + try { + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkPermission(awtEventsManager.permission); + } + awtEventsManager.removeAWTEventListener(listener); + } finally { + unlockAWT(); + } + } + + /** + * Gets the array of all AWT event listeners registered with this Toolkit. + * + * @return the array of all AWT event listeners registered with this + * Toolkit. + */ + public AWTEventListener[] getAWTEventListeners() { + lockAWT(); + try { + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkPermission(awtEventsManager.permission); + } + return awtEventsManager.getAWTEventListeners(); + } finally { + unlockAWT(); + } + } + + /** + * Returns the array of the AWT event listeners registered with this Toolkit + * for the event types corresponding to the specified event mask. + * + * @param eventMask + * the bit mask of event type. + * @return the array of the AWT event listeners registered in this Toolkit + * for the event types corresponding to the specified event mask. + */ + public AWTEventListener[] getAWTEventListeners(long eventMask) { + lockAWT(); + try { + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkPermission(awtEventsManager.permission); + } + return awtEventsManager.getAWTEventListeners(eventMask); + } finally { + unlockAWT(); + } + } + + /** + * Dispatch AWT event. + * + * @param event + * the event. + */ + void dispatchAWTEvent(AWTEvent event) { + awtEventsManager.dispatchAWTEvent(event); + } + + /** + * The Class AWTEventsManager. + */ + final class AWTEventsManager { + + /** + * The permission. + */ + AWTPermission permission = new AWTPermission("listenToAllAWTEvents"); //$NON-NLS-1$ + + /** + * The listeners. + */ + private final AWTListenerList listeners = new AWTListenerList(); + + /** + * Adds the AWT event listener. + * + * @param listener + * the listener. + * @param eventMask + * the event mask. + */ + void addAWTEventListener(AWTEventListener listener, long eventMask) { + if (listener != null) { + listeners.addUserListener(new AWTEventListenerProxy(eventMask, listener)); + } + } + + /** + * Removes the AWT event listener. + * + * @param listener + * the listener. + */ + void removeAWTEventListener(AWTEventListener listener) { + if (listener != null) { + for (AWTEventListenerProxy proxy : listeners.getUserListeners()) { + if (listener == proxy.getListener()) { + listeners.removeUserListener(proxy); + return; + } + } + } + } + + /** + * Gets the AWT event listeners. + * + * @return the AWT event listeners. + */ + AWTEventListener[] getAWTEventListeners() { + HashSet listenersSet = new HashSet(); + for (AWTEventListenerProxy proxy : listeners.getUserListeners()) { + listenersSet.add(proxy.getListener()); + } + return listenersSet.toArray(new AWTEventListener[listenersSet.size()]); + } + + /** + * Gets the AWT event listeners. + * + * @param eventMask + * the event mask. + * @return the AWT event listeners. + */ + AWTEventListener[] getAWTEventListeners(long eventMask) { + HashSet listenersSet = new HashSet(); + for (AWTEventListenerProxy proxy : listeners.getUserListeners()) { + if ((proxy.getEventMask() & eventMask) == eventMask) { + listenersSet.add(proxy.getListener()); + } + } + return listenersSet.toArray(new AWTEventListener[listenersSet.size()]); + } + + /** + * Dispatch AWT event. + * + * @param event + * the event. + */ + void dispatchAWTEvent(AWTEvent event) { + AWTEvent.EventDescriptor descriptor = eventTypeLookup.getEventDescriptor(event); + if (descriptor == null) { + return; + } + for (AWTEventListenerProxy proxy : listeners.getUserListeners()) { + if ((proxy.getEventMask() & descriptor.eventMask) != 0) { + proxy.eventDispatched(event); + } + } + } + } + + /** + * The Class AutoNumber. + */ + static final class AutoNumber { + + /** + * The next component. + */ + int nextComponent = 0; + + /** + * The next canvas. + */ + int nextCanvas = 0; + + /** + * The next panel. + */ + int nextPanel = 0; + + /** + * The next window. + */ + int nextWindow = 0; + + /** + * The next frame. + */ + int nextFrame = 0; + + /** + * The next dialog. + */ + int nextDialog = 0; + + /** + * The next button. + */ + int nextButton = 0; + + /** + * The next menu component. + */ + int nextMenuComponent = 0; + + /** + * The next label. + */ + int nextLabel = 0; + + /** + * The next check box. + */ + int nextCheckBox = 0; + + /** + * The next scrollbar. + */ + int nextScrollbar = 0; + + /** + * The next scroll pane. + */ + int nextScrollPane = 0; + + /** + * The next list. + */ + int nextList = 0; + + /** + * The next choice. + */ + int nextChoice = 0; + + /** + * The next file dialog. + */ + int nextFileDialog = 0; + + /** + * The next text area. + */ + int nextTextArea = 0; + + /** + * The next text field. + */ + int nextTextField = 0; + } + + private class Lock { + } + + /** + * The lock. + */ + private final Object lock = new Lock(); - public DesktopPeer createDesktopPeer() - { - return desktopPeer; - } - - public static Toolkit getDefaultToolkit() - { - return toolkit; - } - - public Clipboard getSystemClipboard() throws HeadlessException - { - return clipboard; - } } diff --git a/app/src/main/java/java/awt/ToolkitImpl.java b/app/src/main/java/java/awt/ToolkitImpl.java new file mode 100644 index 000000000..4bd7ba7f0 --- /dev/null +++ b/app/src/main/java/java/awt/ToolkitImpl.java @@ -0,0 +1,270 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package java.awt; + +import java.awt.im.InputMethodHighlight; +import java.awt.image.ColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.peer.*; +import java.io.Serializable; +import java.net.URL; +import java.util.Hashtable; +import java.util.Map; +import org.apache.harmony.awt.gl.image.*; +import org.apache.harmony.awt.wtk.GraphicsFactory; +import java.awt.datatransfer.*; + +class ToolkitImpl extends Toolkit { + + static final Hashtable imageCache = new Hashtable(); + private final Clipboard mClipboard; + + public ToolkitImpl() { + mClipboard = new Clipboard(); + } + + @Override + public void sync() { + lockAWT(); + try { + } finally { + unlockAWT(); + } + } + + @Override + public int checkImage(Image image, int width, int height, ImageObserver observer) { + lockAWT(); + try { + if (width == 0 || height == 0) { + return ImageObserver.ALLBITS; + } + if (!(image instanceof OffscreenImage)) { + return ImageObserver.ALLBITS; + } + OffscreenImage oi = (OffscreenImage) image; + return oi.checkImage(observer); + } finally { + unlockAWT(); + } + } + + @Override + public Image createImage(ImageProducer producer) { + lockAWT(); + try { + return new OffscreenImage(producer); + } finally { + unlockAWT(); + } + } + + @Override + public Image createImage(byte[] imagedata, int imageoffset, int imagelength) { + lockAWT(); + try { + return new OffscreenImage(new ByteArrayDecodingImageSource(imagedata, imageoffset, + imagelength)); + } finally { + unlockAWT(); + } + } + + @Override + public Image createImage(URL url) { + lockAWT(); + try { + return new OffscreenImage(new URLDecodingImageSource(url)); + } finally { + unlockAWT(); + } + } + + @Override + public Image createImage(String filename) { + lockAWT(); + try { + return new OffscreenImage(new FileDecodingImageSource(filename)); + } finally { + unlockAWT(); + } + } + + @Override + public Clipboard getSystemClipboard() { + lockAWT(); + try { + return mClipboard; + } finally { + unlockAWT(); + } + } + + @Override + public ColorModel getColorModel() { + lockAWT(); + try { + return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice() + .getDefaultConfiguration().getColorModel(); + } finally { + unlockAWT(); + } + } + + @SuppressWarnings("deprecation") + @Override + @Deprecated + public FontMetrics getFontMetrics(Font font) { + lockAWT(); + try { + GraphicsFactory gf = getGraphicsFactory(); + return gf.getFontMetrics(font); + } finally { + unlockAWT(); + } + } + + @Override + public boolean prepareImage(Image image, int width, int height, ImageObserver observer) { + lockAWT(); + try { + if (width == 0 || height == 0) { + return true; + } + if (!(image instanceof OffscreenImage)) { + return true; + } + OffscreenImage oi = (OffscreenImage) image; + return oi.prepareImage(observer); + } finally { + unlockAWT(); + } + } + + @Override + public void beep() { + lockAWT(); + try { + // ???AWT: is there nothing to be implemented here? + } finally { + unlockAWT(); + } + } + + @SuppressWarnings("deprecation") + @Override + @Deprecated + public String[] getFontList() { + lockAWT(); + try { + } finally { + unlockAWT(); + } + return null; + } + + @SuppressWarnings("deprecation") + @Override + @Deprecated + protected FontPeer getFontPeer(String a0, int a1) { + lockAWT(); + try { + return null; + } finally { + unlockAWT(); + } + } + + @Override + public Image getImage(String filename) { + return getImage(filename, this); + } + + static Image getImage(String filename, Toolkit toolkit) { + synchronized (imageCache) { + Image im = (filename == null ? null : imageCache.get(filename)); + + if (im == null) { + try { + im = toolkit.createImage(filename); + imageCache.put(filename, im); + } catch (Exception e) { + } + } + + return im; + } + } + + @Override + public Image getImage(URL url) { + return getImage(url, this); + } + + static Image getImage(URL url, Toolkit toolkit) { + synchronized (imageCache) { + Image im = imageCache.get(url); + if (im == null) { + try { + im = toolkit.createImage(url); + imageCache.put(url, im); + } catch (Exception e) { + } + } + return im; + } + } + + @Override + public int getScreenResolution() throws HeadlessException { + lockAWT(); + try { + return 62; + } finally { + unlockAWT(); + } + } + + @Override + public Dimension getScreenSize() { + lockAWT(); + try { + DisplayMode dm = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDisplayMode(); + return new Dimension(dm.getWidth(), dm.getHeight()); + } finally { + unlockAWT(); + } + } + + @Override + public Map mapInputMethodHighlight( + InputMethodHighlight highlight) throws HeadlessException { + lockAWT(); + try { + return mapInputMethodHighlightImpl(highlight); + } finally { + unlockAWT(); + } + } + + @Override + protected EventQueue getSystemEventQueueImpl() { + return getSystemEventQueueCore().getActiveEventQueue(); + } +} diff --git a/app/src/main/java/java/awt/Window.java b/app/src/main/java/java/awt/Window.java index 6eefb753a..a46e73804 100644 --- a/app/src/main/java/java/awt/Window.java +++ b/app/src/main/java/java/awt/Window.java @@ -56,14 +56,13 @@ public class Window extends Container } if (oldAlwaysOnTop != alwaysOnTop ) { if (isAlwaysOnTopSupported()) { - /* + WindowPeer peer = (WindowPeer)this.peer; synchronized(getTreeLock()) { if (peer != null) { - //peer.setAlwaysOnTop(alwaysOnTop); + // peer.setAlwaysOnTop(alwaysOnTop); } } - */ } firePropertyChange("alwaysOnTop", oldAlwaysOnTop, alwaysOnTop); } diff --git a/app/src/main/java/java/awt/color/CMMException.java b/app/src/main/java/java/awt/color/CMMException.java new file mode 100644 index 000000000..18b9a7e56 --- /dev/null +++ b/app/src/main/java/java/awt/color/CMMException.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ +package java.awt.color; + +/** + * The CMMException is thrown as soon as a native CMM error occurs. + * + * @since Android 1.0 + */ +public class CMMException extends java.lang.RuntimeException { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = 5775558044142994965L; + + /** + * Instantiates a new CMM exception with detail message. + * + * @param s + * the detail message of the exception. + */ + public CMMException (String s) { + super (s); + } +} diff --git a/app/src/main/java/java/awt/color/ColorSpace.java b/app/src/main/java/java/awt/color/ColorSpace.java new file mode 100644 index 000000000..44c491b74 --- /dev/null +++ b/app/src/main/java/java/awt/color/ColorSpace.java @@ -0,0 +1,414 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ +package java.awt.color; + +import java.io.Serializable; + +import org.apache.harmony.awt.gl.color.LUTColorConverter; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The ColorSpace class defines a color space type for a Color and provides + * methods for arrays of color component operations. + * + * @since Android 1.0 + */ +public abstract class ColorSpace implements Serializable { + + /** The Constant serialVersionUID. */ + private static final long serialVersionUID = -409452704308689724L; + + /** + * The Constant TYPE_XYZ indicates XYZ color space type. + */ + public static final int TYPE_XYZ = 0; + + /** + * The Constant TYPE_Lab indicates Lab color space type. + */ + public static final int TYPE_Lab = 1; + + /** + * The Constant TYPE_Luv indicates Luv color space type. + */ + public static final int TYPE_Luv = 2; + + /** + * The Constant TYPE_YCbCr indicates YCbCr color space type. + */ + public static final int TYPE_YCbCr = 3; + + /** + * The Constant TYPE_Yxy indicates Yxy color space type. + */ + public static final int TYPE_Yxy = 4; + + /** + * The Constant TYPE_RGB indicates RGB color space type. + */ + public static final int TYPE_RGB = 5; + + /** + * The Constant TYPE_GRAY indicates Gray color space type. + */ + public static final int TYPE_GRAY = 6; + + /** + * The Constant TYPE_HSV indicates HSV color space type. + */ + public static final int TYPE_HSV = 7; + + /** + * The Constant TYPE_HLS indicates HLS color space type. + */ + public static final int TYPE_HLS = 8; + + /** + * The Constant TYPE_CMYK indicates CMYK color space type. + */ + public static final int TYPE_CMYK = 9; + + /** + * The Constant TYPE_CMY indicates CMY color space type. + */ + public static final int TYPE_CMY = 11; + + /** + * The Constant TYPE_2CLR indicates color spaces with 2 components. + */ + public static final int TYPE_2CLR = 12; + + /** + * The Constant TYPE_3CLR indicates color spaces with 3 components. + */ + public static final int TYPE_3CLR = 13; + + /** + * The Constant TYPE_4CLR indicates color spaces with 4 components. + */ + public static final int TYPE_4CLR = 14; + + /** + * The Constant TYPE_5CLR indicates color spaces with 5 components. + */ + public static final int TYPE_5CLR = 15; + + /** + * The Constant TYPE_6CLR indicates color spaces with 6 components. + */ + public static final int TYPE_6CLR = 16; + + /** + * The Constant TYPE_7CLR indicates color spaces with 7 components. + */ + public static final int TYPE_7CLR = 17; + + /** + * The Constant TYPE_8CLR indicates color spaces with 8 components. + */ + public static final int TYPE_8CLR = 18; + + /** + * The Constant TYPE_9CLR indicates color spaces with 9 components. + */ + public static final int TYPE_9CLR = 19; + + /** + * The Constant TYPE_ACLR indicates color spaces with 10 components. + */ + public static final int TYPE_ACLR = 20; + + /** + * The Constant TYPE_BCLR indicates color spaces with 11 components. + */ + public static final int TYPE_BCLR = 21; + + /** + * The Constant TYPE_CCLR indicates color spaces with 12 components. + */ + public static final int TYPE_CCLR = 22; + + /** + * The Constant TYPE_DCLR indicates color spaces with 13 components. + */ + public static final int TYPE_DCLR = 23; + + /** + * The Constant TYPE_ECLR indicates color spaces with 14 components. + */ + public static final int TYPE_ECLR = 24; + + /** + * The Constant TYPE_FCLR indicates color spaces with 15 components. + */ + public static final int TYPE_FCLR = 25; + + /** + * The Constant CS_sRGB indicates standard RGB color space. + */ + public static final int CS_sRGB = 1000; + + /** + * The Constant CS_LINEAR_RGB indicates linear RGB color space. + */ + public static final int CS_LINEAR_RGB = 1004; + + /** + * The Constant CS_CIEXYZ indicates CIEXYZ conversion color space. + */ + public static final int CS_CIEXYZ = 1001; + + /** + * The Constant CS_PYCC indicates Photo YCC conversion color space. + */ + public static final int CS_PYCC = 1002; + + /** + * The Constant CS_GRAY indicates linear gray scale color space. + */ + public static final int CS_GRAY = 1003; + + /** + * The cs_ gray. + */ + private static ColorSpace cs_Gray = null; + + /** + * The cs_ pycc. + */ + private static ColorSpace cs_PYCC = null; + + /** + * The cs_ ciexyz. + */ + private static ColorSpace cs_CIEXYZ = null; + + /** + * The cs_ lrgb. + */ + private static ColorSpace cs_LRGB = null; + + /** + * The cs_s rgb. + */ + private static ColorSpace cs_sRGB = null; + + /** + * The type. + */ + private int type; + + /** + * The num components. + */ + private int numComponents; + + /** + * Instantiates a ColorSpace with the specified ColorSpace type and number + * of components. + * + * @param type + * the type of color space. + * @param numcomponents + * the number of components. + */ + protected ColorSpace(int type, int numcomponents) { + this.numComponents = numcomponents; + this.type = type; + } + + /** + * Gets the name of the component for the specified component index. + * + * @param idx + * the index of the component. + * @return the name of the component. + */ + public String getName(int idx) { + if (idx < 0 || idx > numComponents - 1) { + // awt.16A=Invalid component index: {0} + throw new IllegalArgumentException(Messages.getString("awt.16A", idx)); //$NON-NLS-1$ + } + + return "Unnamed color component #" + idx; //$NON-NLS-1$ + } + + /** + * Performs the transformation of a color from this ColorSpace into the RGB + * color space. + * + * @param colorvalue + * the color value in this ColorSpace. + * @return the float array with color components in the RGB color space. + */ + public abstract float[] toRGB(float[] colorvalue); + + /** + * Performs the transformation of a color from this ColorSpace into the + * CS_CIEXYZ color space. + * + * @param colorvalue + * the color value in this ColorSpace. + * @return the float array with color components in the CS_CIEXYZ color + * space. + */ + public abstract float[] toCIEXYZ(float[] colorvalue); + + /** + * Performs the transformation of a color from the RGB color space into this + * ColorSpace. + * + * @param rgbvalue + * the float array representing a color in the RGB color space. + * @return the float array with the transformed color components. + */ + public abstract float[] fromRGB(float[] rgbvalue); + + /** + * Performs the transformation of a color from the CS_CIEXYZ color space + * into this ColorSpace. + * + * @param colorvalue + * the float array representing a color in the CS_CIEXYZ color + * space. + * @return the float array with the transformed color components. + */ + public abstract float[] fromCIEXYZ(float[] colorvalue); + + /** + * Gets the minimum normalized color component value for the specified + * component. + * + * @param component + * the component to determine the minimum value. + * @return the minimum normalized value of the component. + */ + public float getMinValue(int component) { + if (component < 0 || component > numComponents - 1) { + // awt.16A=Invalid component index: {0} + throw new IllegalArgumentException(Messages.getString("awt.16A", component)); //$NON-NLS-1$ + } + return 0; + } + + /** + * Gets the maximum normalized color component value for the specified + * component. + * + * @param component + * the component to determine the maximum value. + * @return the maximum normalized value of the component. + */ + public float getMaxValue(int component) { + if (component < 0 || component > numComponents - 1) { + // awt.16A=Invalid component index: {0} + throw new IllegalArgumentException(Messages.getString("awt.16A", component)); //$NON-NLS-1$ + } + return 1; + } + + /** + * Checks if this ColorSpace has CS_sRGB type or not. + * + * @return true, if this ColorSpace has CS_sRGB type, false otherwise. + */ + public boolean isCS_sRGB() { + // If our color space is sRGB, then cs_sRGB + // is already initialized + return (this == cs_sRGB); + } + + /** + * Gets the type of the ColorSpace. + * + * @return the type of the ColorSpace. + */ + public int getType() { + return type; + } + + /** + * Gets the number of components for this ColorSpace. + * + * @return the number of components. + */ + public int getNumComponents() { + return numComponents; + } + + + /** + * Gets the single instance of ColorSpace with the specified ColorSpace: + * CS_sRGB, CS_LINEAR_RGB, CS_CIEXYZ, CS_GRAY, or CS_PYCC. + * + * @param colorspace + * the identifier of the specified Colorspace. + * @return the single instance of the desired ColorSpace. + */ + public static ColorSpace getInstance(int colorspace) { + switch (colorspace) { + case CS_sRGB: + if (cs_sRGB == null) { + cs_sRGB = new ICC_ColorSpace( + new ICC_ProfileStub(CS_sRGB)); + LUTColorConverter.sRGB_CS = cs_sRGB; + //ICC_Profile.getInstance (CS_sRGB)); + } + return cs_sRGB; + case CS_CIEXYZ: + if (cs_CIEXYZ == null) { + cs_CIEXYZ = new ICC_ColorSpace( + new ICC_ProfileStub(CS_CIEXYZ)); + //ICC_Profile.getInstance (CS_CIEXYZ)); + } + return cs_CIEXYZ; + case CS_GRAY: + if (cs_Gray == null) { + cs_Gray = new ICC_ColorSpace( + new ICC_ProfileStub(CS_GRAY)); + LUTColorConverter.LINEAR_GRAY_CS = cs_Gray; + //ICC_Profile.getInstance (CS_GRAY)); + } + return cs_Gray; + case CS_PYCC: + if (cs_PYCC == null) { + cs_PYCC = new ICC_ColorSpace( + new ICC_ProfileStub(CS_PYCC)); + //ICC_Profile.getInstance (CS_PYCC)); + } + return cs_PYCC; + case CS_LINEAR_RGB: + if (cs_LRGB == null) { + cs_LRGB = new ICC_ColorSpace( + new ICC_ProfileStub(CS_LINEAR_RGB)); + LUTColorConverter.LINEAR_GRAY_CS = cs_Gray; + //ICC_Profile.getInstance (CS_LINEAR_RGB)); + } + return cs_LRGB; + default: + } + + // Unknown argument passed + // awt.16B=Not a predefined colorspace + throw new IllegalArgumentException(Messages.getString("Not a predefined colorspace")); //$NON-NLS-1$ + } + +} \ No newline at end of file diff --git a/app/src/main/java/java/awt/color/ICC_ColorSpace.java b/app/src/main/java/java/awt/color/ICC_ColorSpace.java new file mode 100644 index 000000000..5b4d7e99f --- /dev/null +++ b/app/src/main/java/java/awt/color/ICC_ColorSpace.java @@ -0,0 +1,468 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ +package java.awt.color; + +import org.apache.harmony.awt.gl.color.ColorConverter; +import org.apache.harmony.awt.gl.color.ColorScaler; +import org.apache.harmony.awt.gl.color.ICC_Transform; +import org.apache.harmony.awt.internal.nls.Messages; + +import java.io.*; + +/** + * This class implements the abstract class ColorSpace and represents device + * independent and device dependent color spaces. This color space is based on + * the International Color Consortium Specification (ICC) File Format for Color + * Profiles: http://www.color.org + * + * @since Android 1.0 + */ +public class ICC_ColorSpace extends ColorSpace { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = 3455889114070431483L; + + // Need to keep compatibility with serialized form + /** + * The Constant serialPersistentFields. + */ + private static final ObjectStreamField[] + serialPersistentFields = { + new ObjectStreamField("thisProfile", ICC_Profile.class), //$NON-NLS-1$ + new ObjectStreamField("minVal", float[].class), //$NON-NLS-1$ + new ObjectStreamField("maxVal", float[].class), //$NON-NLS-1$ + new ObjectStreamField("diffMinMax", float[].class), //$NON-NLS-1$ + new ObjectStreamField("invDiffMinMax", float[].class), //$NON-NLS-1$ + new ObjectStreamField("needScaleInit", Boolean.TYPE) //$NON-NLS-1$ + }; + + + /** + * According to ICC specification (from http://www.color.org) "For the + * CIEXYZ encoding, each component (X, Y, and Z) is encoded as a + * u1Fixed15Number". This means that max value for this encoding is 1 + + * (32767/32768) + */ + private static final float MAX_XYZ = 1f + (32767f/32768f); + + /** + * The Constant MAX_SHORT. + */ + private static final float MAX_SHORT = 65535f; + + /** + * The Constant INV_MAX_SHORT. + */ + private static final float INV_MAX_SHORT = 1f/MAX_SHORT; + + /** + * The Constant SHORT2XYZ_FACTOR. + */ + private static final float SHORT2XYZ_FACTOR = MAX_XYZ/MAX_SHORT; + + /** + * The Constant XYZ2SHORT_FACTOR. + */ + private static final float XYZ2SHORT_FACTOR = MAX_SHORT/MAX_XYZ; + + /** + * The profile. + */ + private ICC_Profile profile = null; + + /** + * The min values. + */ + private float minValues[] = null; + + /** + * The max values. + */ + private float maxValues[] = null; + + // cache transforms here - performance gain + /** + * The to rgb transform. + */ + private ICC_Transform toRGBTransform = null; + + /** + * The from rgb transform. + */ + private ICC_Transform fromRGBTransform = null; + + /** + * The to xyz transform. + */ + private ICC_Transform toXYZTransform = null; + + /** + * The from xyz transform. + */ + private ICC_Transform fromXYZTransform = null; + + /** + * The converter. + */ + private final ColorConverter converter = new ColorConverter(); + + /** + * The scaler. + */ + private final ColorScaler scaler = new ColorScaler(); + + /** + * The scaling data loaded. + */ + private boolean scalingDataLoaded = false; + + /** + * The resolved deserialized inst. + */ + private ICC_ColorSpace resolvedDeserializedInst; + + /** + * Instantiates a new ICC color space from an ICC_Profile object. + * + * @param pf + * the ICC_Profile object. + */ + public ICC_ColorSpace(ICC_Profile pf) { + super(pf.getColorSpaceType(), pf.getNumComponents()); + + int pfClass = pf.getProfileClass(); + + switch (pfClass) { + case ICC_Profile.CLASS_COLORSPACECONVERSION: + case ICC_Profile.CLASS_DISPLAY: + case ICC_Profile.CLASS_OUTPUT: + case ICC_Profile.CLASS_INPUT: + break; // OK, it is color conversion profile + default: + // awt.168=Invalid profile class. + throw new IllegalArgumentException(Messages.getString("awt.168")); //$NON-NLS-1$ + } + + profile = pf; + fillMinMaxValues(); + } + + /** + * Gets the ICC_Profile for this ICC_ColorSpace. + * + * @return the ICC_Profile for this ICC_ColorSpace. + */ + public ICC_Profile getProfile() { + if (profile instanceof ICC_ProfileStub) { + profile = ((ICC_ProfileStub) profile).loadProfile(); + } + + return profile; + } + + /** + * Performs the transformation of a color from this ColorSpace into the RGB + * color space. + * + * @param colorvalue + * the color value in this ColorSpace. + * @return the float array with color components in the RGB color space. + */ + @Override + public float[] toRGB(float[] colorvalue) { + if (toRGBTransform == null) { + ICC_Profile sRGBProfile = + ((ICC_ColorSpace) ColorSpace.getInstance(CS_sRGB)).getProfile(); + ICC_Profile[] profiles = {getProfile(), sRGBProfile}; + toRGBTransform = new ICC_Transform(profiles); + if (!scalingDataLoaded) { + scaler.loadScalingData(this); + scalingDataLoaded = true; + } + } + + short[] data = new short[getNumComponents()]; + + scaler.scale(colorvalue, data, 0); + + short[] converted = + converter.translateColor(toRGBTransform, data, null); + + // unscale to sRGB + float[] res = new float[3]; + + res[0] = ((converted[0] & 0xFFFF)) * INV_MAX_SHORT; + res[1] = ((converted[1] & 0xFFFF)) * INV_MAX_SHORT; + res[2] = ((converted[2] & 0xFFFF)) * INV_MAX_SHORT; + + return res; + } + + /** + * Performs the transformation of a color from this ColorSpace into the + * CS_CIEXYZ color space. + * + * @param colorvalue + * the color value in this ColorSpace. + * @return the float array with color components in the CS_CIEXYZ color + * space. + */ + @Override + public float[] toCIEXYZ(float[] colorvalue) { + if (toXYZTransform == null) { + ICC_Profile xyzProfile = + ((ICC_ColorSpace) ColorSpace.getInstance(CS_CIEXYZ)).getProfile(); + ICC_Profile[] profiles = {getProfile(), xyzProfile}; + try { + int[] intents = { + ICC_Profile.icRelativeColorimetric, + ICC_Profile.icPerceptual}; + toXYZTransform = new ICC_Transform(profiles, intents); + } catch (CMMException e) { // No such tag, use what we can + toXYZTransform = new ICC_Transform(profiles); + } + + if (!scalingDataLoaded) { + scaler.loadScalingData(this); + scalingDataLoaded = true; + } + } + + short[] data = new short[getNumComponents()]; + + scaler.scale(colorvalue, data, 0); + + short[] converted = + converter.translateColor(toXYZTransform, data, null); + + // unscale to XYZ + float[] res = new float[3]; + + res[0] = ((converted[0] & 0xFFFF)) * SHORT2XYZ_FACTOR; + res[1] = ((converted[1] & 0xFFFF)) * SHORT2XYZ_FACTOR; + res[2] = ((converted[2] & 0xFFFF)) * SHORT2XYZ_FACTOR; + + return res; + } + + /** + * Performs the transformation of a color from the RGB color space into this + * ColorSpace. + * + * @param rgbvalue + * the float array representing a color in the RGB color space. + * @return the float array with the transformed color components. + */ + @Override + public float[] fromRGB(float[] rgbvalue) { + if (fromRGBTransform == null) { + ICC_Profile sRGBProfile = + ((ICC_ColorSpace) ColorSpace.getInstance(CS_sRGB)).getProfile(); + ICC_Profile[] profiles = {sRGBProfile, getProfile()}; + fromRGBTransform = new ICC_Transform(profiles); + if (!scalingDataLoaded) { + scaler.loadScalingData(this); + scalingDataLoaded = true; + } + } + + // scale rgb value to short + short[] scaledRGBValue = new short[3]; + scaledRGBValue[0] = (short)(rgbvalue[0] * MAX_SHORT + 0.5f); + scaledRGBValue[1] = (short)(rgbvalue[1] * MAX_SHORT + 0.5f); + scaledRGBValue[2] = (short)(rgbvalue[2] * MAX_SHORT + 0.5f); + + short[] converted = + converter.translateColor(fromRGBTransform, scaledRGBValue, null); + + float[] res = new float[getNumComponents()]; + + scaler.unscale(res, converted, 0); + + return res; + } + + /** + * Performs the transformation of a color from the CS_CIEXYZ color space + * into this ColorSpace. + * + * @param xyzvalue + * the float array representing a color in the CS_CIEXYZ color + * space. + * @return the float array with the transformed color components. + */ + @Override + public float[] fromCIEXYZ(float[] xyzvalue) { + if (fromXYZTransform == null) { + ICC_Profile xyzProfile = + ((ICC_ColorSpace) ColorSpace.getInstance(CS_CIEXYZ)).getProfile(); + ICC_Profile[] profiles = {xyzProfile, getProfile()}; + try { + int[] intents = { + ICC_Profile.icPerceptual, + ICC_Profile.icRelativeColorimetric}; + fromXYZTransform = new ICC_Transform(profiles, intents); + } catch (CMMException e) { // No such tag, use what we can + fromXYZTransform = new ICC_Transform(profiles); + } + + if (!scalingDataLoaded) { + scaler.loadScalingData(this); + scalingDataLoaded = true; + } + + } + + // scale xyz value to short + short[] scaledXYZValue = new short[3]; + scaledXYZValue[0] = (short)(xyzvalue[0] * XYZ2SHORT_FACTOR + 0.5f); + scaledXYZValue[1] = (short)(xyzvalue[1] * XYZ2SHORT_FACTOR + 0.5f); + scaledXYZValue[2] = (short)(xyzvalue[2] * XYZ2SHORT_FACTOR + 0.5f); + + short[] converted = + converter.translateColor(fromXYZTransform, scaledXYZValue, null); + + float[] res = new float[getNumComponents()]; + + scaler.unscale(res, converted, 0); + + return res; + } + + /** + * Gets the minimum normalized color component value for the specified + * component. + * + * @param component + * the component to determine the minimum value. + * @return the minimum normalized value of the component. + */ + @Override + public float getMinValue(int component) { + if ((component < 0) || (component > this.getNumComponents() - 1)) { + // awt.169=Component index out of range + throw new IllegalArgumentException(Messages.getString("awt.169")); //$NON-NLS-1$ + } + + return minValues[component]; + } + + /** + * Gets the maximum normalized color component value for the specified + * component. + * + * @param component + * the component to determine the maximum value. + * @return the maximum normalized value of the component. + */ + @Override + public float getMaxValue(int component) { + if ((component < 0) || (component > this.getNumComponents() - 1)) { + // awt.169=Component index out of range + throw new IllegalArgumentException(Messages.getString("awt.169")); //$NON-NLS-1$ + } + + return maxValues[component]; + } + + /** + * Fill min max values. + */ + private void fillMinMaxValues() { + int n = getNumComponents(); + maxValues = new float[n]; + minValues = new float[n]; + switch (getType()) { + case ColorSpace.TYPE_XYZ: + minValues[0] = 0; + minValues[1] = 0; + minValues[2] = 0; + maxValues[0] = MAX_XYZ; + maxValues[1] = MAX_XYZ; + maxValues[2] = MAX_XYZ; + break; + case ColorSpace.TYPE_Lab: + minValues[0] = 0; + minValues[1] = -128; + minValues[2] = -128; + maxValues[0] = 100; + maxValues[1] = 127; + maxValues[2] = 127; + break; + default: + for(int i=0; i() { + public FileInputStream run() { + FileInputStream fiStream = null; + + // Open absolute path + try { + fiStream = new FileInputStream(fName); + if (fiStream != null) { + return fiStream; + } + } catch (FileNotFoundException e) { + } + + // Check java.iccprofile.path entries + fiStream = tryPath(System.getProperty("java.iccprofile.path"), fName); //$NON-NLS-1$ + if (fiStream != null) { + return fiStream; + } + + // Check java.class.path entries + fiStream = tryPath(System.getProperty("java.class.path"), fName); //$NON-NLS-1$ + if (fiStream != null) { + return fiStream; + } + + // Check directory with java sample profiles + String home = System.getProperty("java.home"); //$NON-NLS-1$ + if (home != null) { + fiStream = tryPath(home + File.separatorChar + + "lib" + File.separatorChar + "cmm", fName //$NON-NLS-1$ //$NON-NLS-2$ + ); + } + + return fiStream; + } + }); + + if (fiStream == null) { + // awt.161=Unable to open file {0} + throw new IOException(Messages.getString("awt.161", fileName)); //$NON-NLS-1$ + } + + ICC_Profile pf = getInstance(fiStream); + fiStream.close(); + return pf; + } + + /** + * Gets the single instance of ICC_Profile with data in the specified + * InputStream. + * + * @param s + * the InputStream with ICC profile data. + * @return single instance of ICC_Profile. + * @throws IOException + * if an I/O exception has occurred during reading from + * InputStream. + * @throws IllegalArgumentException + * if the file does not contain valid ICC Profile data. + */ + public static ICC_Profile getInstance(InputStream s) throws IOException { + byte[] header = new byte[headerSize]; + // awt.162=Invalid ICC Profile Data + String invalidDataMessage = Messages.getString("awt.162"); //$NON-NLS-1$ + + // Get header from the input stream + if (s.read(header) != headerSize) { + throw new IllegalArgumentException(invalidDataMessage); + } + + // Check the profile data for consistency + if (ICC_ProfileHelper.getBigEndianFromByteArray(header, icHdrMagic) != headerMagicNumber) { + throw new IllegalArgumentException(invalidDataMessage); + } + + // Get profile size from header, create an array for profile data + int profileSize = ICC_ProfileHelper.getBigEndianFromByteArray(header, icHdrSize); + byte[] profileData = new byte[profileSize]; + + // Copy header into it + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(header, 0, profileData, 0, headerSize); + + // Read the profile itself + if (s.read(profileData, headerSize, profileSize - headerSize) != profileSize - headerSize) { + throw new IllegalArgumentException(invalidDataMessage); + } + + return getInstance(profileData); + } + + /** + * Gets the single instance of ICC_Profile from the specified data in a byte + * array. + * + * @param data + * the byte array of ICC profile. + * @return single instance of ICC_Profile from the specified data in a byte + * array. + * @throws IllegalArgumentException + * if the file does not contain valid ICC Profile data. + */ + public static ICC_Profile getInstance(byte[] data) { + ICC_Profile res = null; + + try { + res = new ICC_Profile(data); + } catch (CMMException e) { + // awt.162=Invalid ICC Profile Data + throw new IllegalArgumentException(Messages.getString("awt.162")); //$NON-NLS-1$ + } + + if (System.getProperty("os.name").toLowerCase().indexOf("windows") >= 0) { //$NON-NLS-1$ //$NON-NLS-2$ + try { + if (res.getColorSpaceType() == ColorSpace.TYPE_RGB + && res.getDataSize(icSigMediaWhitePointTag) > 0 + && res.getDataSize(icSigRedColorantTag) > 0 + && res.getDataSize(icSigGreenColorantTag) > 0 + && res.getDataSize(icSigBlueColorantTag) > 0 + && res.getDataSize(icSigRedTRCTag) > 0 + && res.getDataSize(icSigGreenTRCTag) > 0 + && res.getDataSize(icSigBlueTRCTag) > 0) { + res = new ICC_ProfileRGB(res.getProfileHandle()); + } else if (res.getColorSpaceType() == ColorSpace.TYPE_GRAY + && res.getDataSize(icSigMediaWhitePointTag) > 0 + && res.getDataSize(icSigGrayTRCTag) > 0) { + res = new ICC_ProfileGray(res.getProfileHandle()); + } + + } catch (CMMException e) { /* return res in this case */ + } + } + + return res; + } + + /** + * Gets the single instance of ICC_Profile with the specific color space + * defined by the ColorSpace class: CS_sRGB, CS_LINEAR_RGB, CS_CIEXYZ, + * CS_PYCC, CS_GRAY. + * + * @param cspace + * the type of color space defined in the ColorSpace class. + * @return single instance of ICC_Profile. + * @throws IllegalArgumentException + * is not one of the defined color space types. + */ + public static ICC_Profile getInstance(int cspace) { + try { + switch (cspace) { + + case ColorSpace.CS_sRGB: + if (sRGBProfile == null) { + sRGBProfile = getInstance("sRGB.pf"); //$NON-NLS-1$ + } + return sRGBProfile; + + case ColorSpace.CS_CIEXYZ: + if (xyzProfile == null) { + xyzProfile = getInstance("CIEXYZ.pf"); //$NON-NLS-1$ + } + return xyzProfile; + + case ColorSpace.CS_GRAY: + if (grayProfile == null) { + grayProfile = getInstance("GRAY.pf"); //$NON-NLS-1$ + } + return grayProfile; + + case ColorSpace.CS_PYCC: + if (pyccProfile == null) { + pyccProfile = getInstance("PYCC.pf"); //$NON-NLS-1$ + } + return pyccProfile; + + case ColorSpace.CS_LINEAR_RGB: + if (linearRGBProfile == null) { + linearRGBProfile = getInstance("LINEAR_RGB.pf"); //$NON-NLS-1$ + } + return linearRGBProfile; + } + + } catch (IOException e) { + // awt.163=Can't open color profile + throw new IllegalArgumentException(Messages.getString("Can't open color profile")); //$NON-NLS-1$ + } + + // awt.164=Not a predefined color space + throw new IllegalArgumentException(Messages.getString("Not a predefined color space")); //$NON-NLS-1$ + } + + /** + * Reads an integer from the profile header at the specified position. + * + * @param idx + * - offset in bytes from the beginning of the header + * @return the integer value from header + */ + private int getIntFromHeader(int idx) { + if (headerData == null) { + headerData = getData(icSigHead); + } + + return ((headerData[idx] & 0xFF) << 24) | ((headerData[idx + 1] & 0xFF) << 16) + | ((headerData[idx + 2] & 0xFF) << 8) | ((headerData[idx + 3] & 0xFF)); + } + + /** + * Reads byte from the profile header at the specified position. + * + * @param idx + * - offset in bytes from the beginning of the header + * @return the byte from header + */ + private byte getByteFromHeader(int idx) { + if (headerData == null) { + headerData = getData(icSigHead); + } + + return headerData[idx]; + } + + /** + * Converts ICC color space signature to the java predefined color space + * type. + * + * @param signature + * the signature + * @return the int + */ + private int csFromSignature(int signature) { + switch (signature) { + case icSigRgbData: + return ColorSpace.TYPE_RGB; + case icSigXYZData: + return ColorSpace.TYPE_XYZ; + case icSigCmykData: + return ColorSpace.TYPE_CMYK; + case icSigLabData: + return ColorSpace.TYPE_Lab; + case icSigGrayData: + return ColorSpace.TYPE_GRAY; + case icSigHlsData: + return ColorSpace.TYPE_HLS; + case icSigLuvData: + return ColorSpace.TYPE_Luv; + case icSigYCbCrData: + return ColorSpace.TYPE_YCbCr; + case icSigYxyData: + return ColorSpace.TYPE_Yxy; + case icSigHsvData: + return ColorSpace.TYPE_HSV; + case icSigCmyData: + return ColorSpace.TYPE_CMY; + case icSigSpace2CLR: + return ColorSpace.TYPE_2CLR; + case icSigSpace3CLR: + return ColorSpace.TYPE_3CLR; + case icSigSpace4CLR: + return ColorSpace.TYPE_4CLR; + case icSigSpace5CLR: + return ColorSpace.TYPE_5CLR; + case icSigSpace6CLR: + return ColorSpace.TYPE_6CLR; + case icSigSpace7CLR: + return ColorSpace.TYPE_7CLR; + case icSigSpace8CLR: + return ColorSpace.TYPE_8CLR; + case icSigSpace9CLR: + return ColorSpace.TYPE_9CLR; + case icSigSpaceACLR: + return ColorSpace.TYPE_ACLR; + case icSigSpaceBCLR: + return ColorSpace.TYPE_BCLR; + case icSigSpaceCCLR: + return ColorSpace.TYPE_CCLR; + case icSigSpaceDCLR: + return ColorSpace.TYPE_DCLR; + case icSigSpaceECLR: + return ColorSpace.TYPE_ECLR; + case icSigSpaceFCLR: + return ColorSpace.TYPE_FCLR; + default: + } + + // awt.165=Color space doesn't comply with ICC specification + throw new IllegalArgumentException(Messages.getString("awt.165")); //$NON-NLS-1$ + } + + /** + * Gets the profile handle. + * + * @return the profile handle + */ + private long getProfileHandle() { + handleStolen = true; + return profileHandle; + } + + /** + * Gets the data size. + * + * @param tagSignature + * the tag signature + * @return the data size + */ + private int getDataSize(int tagSignature) { + return NativeCMM.cmmGetProfileElementSize(profileHandle, tagSignature); + } + + /** + * Reads XYZ value from the tag data. + * + * @param tagSignature + * the tag signature + * @return the XYZ value + */ + float[] getXYZValue(int tagSignature) { + float[] res = new float[3]; + byte[] data = getData(tagSignature); + + // Convert from ICC s15Fixed16Number type + // 1 (float) = 0x10000 (s15Fixed16Number), + // hence dividing by 0x10000 + res[0] = ICC_ProfileHelper.getIntFromByteArray(data, 0) / 65536.f; + res[1] = ICC_ProfileHelper.getIntFromByteArray(data, 4) / 65536.f; + res[2] = ICC_ProfileHelper.getIntFromByteArray(data, 8) / 65536.f; + + return res; + } + + /** + * Gets the media white point. + * + * @return the media white point. + */ + float[] getMediaWhitePoint() { + return getXYZValue(icSigMediaWhitePointTag); + } + + /** + * If TRC is not a table returns gamma via return value and sets dataTRC to + * null. If TRC is a table returns 0 and fills dataTRC with values. + * + * @param tagSignature + * the tag signature + * @param dataTRC + * the data trc + * @return - gamma or zero if TRC is a table + */ + private float getGammaOrTRC(int tagSignature, short[] dataTRC) { + byte[] data = getData(tagSignature); + int trcSize = ICC_ProfileHelper.getIntFromByteArray(data, icCurveCount); + + dataTRC = null; + + if (trcSize == 0) { + return 1.0f; + } + + if (trcSize == 1) { + // Cast from ICC u8Fixed8Number to float + return ICC_ProfileHelper.getShortFromByteArray(data, icCurveData) / 256.f; + } + + // TRC is a table + dataTRC = new short[trcSize]; + for (int i = 0, pos = icCurveData; i < trcSize; i++, pos += 2) { + dataTRC[i] = ICC_ProfileHelper.getShortFromByteArray(data, pos); + } + return 0; + } + + /** + * Gets the gamma. + * + * @param tagSignature + * the tag signature + * @return the gamma + */ + float getGamma(int tagSignature) { + short[] dataTRC = null; + float gamma = getGammaOrTRC(tagSignature, dataTRC); + + if (dataTRC == null) { + return gamma; + } + // awt.166=TRC is not a simple gamma value. + throw new ProfileDataException(Messages.getString("awt.166")); //$NON-NLS-1$ + } + + /** + * Gets the TRC. + * + * @param tagSignature + * the tag signature + * @return the tRC + */ + short[] getTRC(int tagSignature) { + short[] dataTRC = null; + getGammaOrTRC(tagSignature, dataTRC); + + if (dataTRC == null) { + // awt.167=TRC is a gamma value, not a table. + throw new ProfileDataException(Messages.getString("awt.167")); //$NON-NLS-1$ + } + return dataTRC; + } +} diff --git a/app/src/main/java/java/awt/color/ICC_ProfileGray.java b/app/src/main/java/java/awt/color/ICC_ProfileGray.java new file mode 100644 index 000000000..f74810174 --- /dev/null +++ b/app/src/main/java/java/awt/color/ICC_ProfileGray.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ +package java.awt.color; + +/** + * The ICC_ProfileGray class represent profiles with TYPE_GRAY color space type, + * and includes the grayTRCTag and mediaWhitePointTag tags. The gray component + * can be transformed from a GRAY device profile color space to the CIEXYZ + * Profile through the tone reproduction curve (TRC): + *

+ * PCSY = grayTRC[deviceGray] + * + * @since Android 1.0 + */ +public class ICC_ProfileGray extends ICC_Profile { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = -1124721290732002649L; + + /** + * Instantiates a new iC c_ profile gray. + * + * @param profileHandle + * the profile handle + */ + ICC_ProfileGray(long profileHandle) { + super(profileHandle); + } + + /** + * Gets the TRC as an array of shorts. + * + * @return the short array of the TRC. + */ + public short[] getTRC() { + return super.getTRC(icSigGrayTRCTag); + } + + /** + * Gets the media white point. + * + * @return the media white point + */ + @Override + public float[] getMediaWhitePoint() { + return super.getMediaWhitePoint(); + } + + /** + * Gets a gamma value representing the tone reproduction curve (TRC). + * + * @return the gamma value representing the tone reproduction curve (TRC). + */ + public float getGamma() { + return super.getGamma(icSigGrayTRCTag); + } +} + diff --git a/app/src/main/java/java/awt/color/ICC_ProfileRGB.java b/app/src/main/java/java/awt/color/ICC_ProfileRGB.java new file mode 100644 index 000000000..9c6010fcd --- /dev/null +++ b/app/src/main/java/java/awt/color/ICC_ProfileRGB.java @@ -0,0 +1,154 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ +package java.awt.color; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The ICC_ProfileRGB class represents profiles with RGB color space type and + * contains the redColorantTag, greenColorantTag, blueColorantTag, redTRCTag, + * greenTRCTag, blueTRCTag, and mediaWhitePointTag tags. + * + * @since Android 1.0 + */ +public class ICC_ProfileRGB extends ICC_Profile { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = 8505067385152579334L; + + /** + * Instantiates a new RGB ICC_Profile. + * + * @param profileHandle + * the profile handle + */ + ICC_ProfileRGB(long profileHandle) { + super(profileHandle); + } + + /** + * The Constant REDCOMPONENT indicates the red component. + */ + public static final int REDCOMPONENT = 0; + + /** + * The Constant GREENCOMPONENT indicates the green component. + */ + public static final int GREENCOMPONENT = 1; + + /** + * The Constant BLUECOMPONENT indicates the blue component. + */ + public static final int BLUECOMPONENT = 2; + + // awt.15E=Unknown component. Must be REDCOMPONENT, GREENCOMPONENT or BLUECOMPONENT. + /** + * The Constant UNKNOWN_COMPONENT_MSG. + */ + private static final String UNKNOWN_COMPONENT_MSG = Messages + .getString("awt.15E"); //$NON-NLS-1$ + + /** + * Gets the TRC. + * + * @param component + * the tag signature. + * @return the TRC value. + */ + @Override + public short[] getTRC(int component) { + switch (component) { + case REDCOMPONENT: + return super.getTRC(icSigRedTRCTag); + case GREENCOMPONENT: + return super.getTRC(icSigGreenTRCTag); + case BLUECOMPONENT: + return super.getTRC(icSigBlueTRCTag); + default: + } + + throw new IllegalArgumentException(UNKNOWN_COMPONENT_MSG); + } + + /** + * Gets the gamma. + * + * @param component + * the tag signature. + * @return the gamma value. + */ + @Override + public float getGamma(int component) { + switch (component) { + case REDCOMPONENT: + return super.getGamma(icSigRedTRCTag); + case GREENCOMPONENT: + return super.getGamma(icSigGreenTRCTag); + case BLUECOMPONENT: + return super.getGamma(icSigBlueTRCTag); + default: + } + + throw new IllegalArgumentException(UNKNOWN_COMPONENT_MSG); + } + + /** + * Gets a float matrix which contains the X, Y, and Z components of the + * profile's redColorantTag, greenColorantTag, and blueColorantTag. + * + * @return the float matrix which contains the X, Y, and Z components of the + * profile's redColorantTag, greenColorantTag, and blueColorantTag. + */ + public float[][] getMatrix() { + float [][] m = new float[3][3]; // The matrix + + float[] redXYZ = getXYZValue(icSigRedColorantTag); + float[] greenXYZ = getXYZValue(icSigGreenColorantTag); + float[] blueXYZ = getXYZValue(icSigBlueColorantTag); + + m[0][0] = redXYZ[0]; + m[1][0] = redXYZ[1]; + m[2][0] = redXYZ[2]; + + m[0][1] = greenXYZ[0]; + m[1][1] = greenXYZ[1]; + m[2][1] = greenXYZ[2]; + + m[0][2] = blueXYZ[0]; + m[1][2] = blueXYZ[1]; + m[2][2] = blueXYZ[2]; + + return m; + } + + /** + * Gets the media white point. + * + * @return the media white point. + */ + @Override + public float[] getMediaWhitePoint() { + return super.getMediaWhitePoint(); + } +} + diff --git a/app/src/main/java/java/awt/color/ICC_ProfileStub.java b/app/src/main/java/java/awt/color/ICC_ProfileStub.java new file mode 100644 index 000000000..bc04c8a66 --- /dev/null +++ b/app/src/main/java/java/awt/color/ICC_ProfileStub.java @@ -0,0 +1,173 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ + +package java.awt.color; + +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectStreamException; +import java.io.OutputStream; + +import org.apache.harmony.awt.internal.nls.Messages; + +final class ICC_ProfileStub extends ICC_Profile { + private static final long serialVersionUID = 501389760875253507L; + + transient int colorspace; + + public ICC_ProfileStub(int csSpecifier) { + switch (csSpecifier) { + case ColorSpace.CS_sRGB: + case ColorSpace.CS_CIEXYZ: + case ColorSpace.CS_LINEAR_RGB: + case ColorSpace.CS_PYCC: + case ColorSpace.CS_GRAY: + break; + default: + // awt.15D=Invalid colorspace + throw new IllegalArgumentException(Messages.getString("awt.15D")); //$NON-NLS-1$ + } + colorspace = csSpecifier; + } + + @Override + public void write(String fileName) throws IOException { + throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$ + } + + /** + * Serializable implementation + * + * @throws ObjectStreamException + */ + private Object writeReplace() throws ObjectStreamException { + return loadProfile(); + } + + @Override + public void write(OutputStream s) throws IOException { + throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$ + } + + @Override + public void setData(int tagSignature, byte[] tagData) { + throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$ + } + + @Override + public byte[] getData(int tagSignature) { + throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$ + } + + @Override + public byte[] getData() { + throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$ + } + + @Override + protected void finalize() { + } + + @Override + public int getProfileClass() { + return CLASS_COLORSPACECONVERSION; + } + + @Override + public int getPCSType() { + throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$ + } + + @Override + public int getNumComponents() { + switch (colorspace) { + case ColorSpace.CS_sRGB: + case ColorSpace.CS_CIEXYZ: + case ColorSpace.CS_LINEAR_RGB: + case ColorSpace.CS_PYCC: + return 3; + case ColorSpace.CS_GRAY: + return 1; + default: + throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$ + } + } + + @Override + public int getMinorVersion() { + throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$ + } + + @Override + public int getMajorVersion() { + throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$ + } + + @Override + public int getColorSpaceType() { + switch (colorspace) { + case ColorSpace.CS_sRGB: + case ColorSpace.CS_LINEAR_RGB: + return ColorSpace.TYPE_RGB; + case ColorSpace.CS_CIEXYZ: + return ColorSpace.TYPE_XYZ; + case ColorSpace.CS_PYCC: + return ColorSpace.TYPE_3CLR; + case ColorSpace.CS_GRAY: + return ColorSpace.TYPE_GRAY; + default: + throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$ + } + } + + public static ICC_Profile getInstance(String fileName) throws IOException { + throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$ + } + + public static ICC_Profile getInstance(InputStream s) throws IOException { + throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$ + } + + public static ICC_Profile getInstance(byte[] data) { + throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$ + } + + public static ICC_Profile getInstance(int cspace) { + throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$ + } + + public ICC_Profile loadProfile() { + switch (colorspace) { + case ColorSpace.CS_sRGB: + return ICC_Profile.getInstance(ColorSpace.CS_sRGB); + case ColorSpace.CS_GRAY: + return ICC_Profile.getInstance(ColorSpace.CS_GRAY); + case ColorSpace.CS_CIEXYZ: + return ICC_Profile.getInstance(ColorSpace.CS_CIEXYZ); + case ColorSpace.CS_LINEAR_RGB: + return ICC_Profile.getInstance(ColorSpace.CS_LINEAR_RGB); + case ColorSpace.CS_PYCC: + return ICC_Profile.getInstance(ColorSpace.CS_PYCC); + default: + throw new UnsupportedOperationException("Stub cannot perform this operation"); //$NON-NLS-1$ + } + } +} \ No newline at end of file diff --git a/app/src/main/java/java/awt/color/ProfileDataException.java b/app/src/main/java/java/awt/color/ProfileDataException.java new file mode 100644 index 000000000..335f314ca --- /dev/null +++ b/app/src/main/java/java/awt/color/ProfileDataException.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ +package java.awt.color; + +/** + * The ProfileDataException class represents an error which occurs while + * accessing or processing an ICC_Profile object. + * + * @since Android 1.0 + */ +public class ProfileDataException extends RuntimeException { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = 7286140888240322498L; + + /** + * Instantiates a new profile data exception with detailed message. + * + * @param s + * the detailed message of the exception. + */ + public ProfileDataException(String s) { + super(s); + } + +} + diff --git a/app/src/main/java/java/awt/color/package.html b/app/src/main/java/java/awt/color/package.html new file mode 100644 index 000000000..609d963a8 --- /dev/null +++ b/app/src/main/java/java/awt/color/package.html @@ -0,0 +1,8 @@ + + +

+ This package contains classes representing color spaces and profiles based on the International Color Consortium (ICC) Profile Format Specification. +

+ @since Android 1.0 + + diff --git a/app/src/main/java/java/awt/datatransfer/Clipboard.java b/app/src/main/java/java/awt/datatransfer/Clipboard.java index 7eb6fda5f..211cf3b4a 100644 --- a/app/src/main/java/java/awt/datatransfer/Clipboard.java +++ b/app/src/main/java/java/awt/datatransfer/Clipboard.java @@ -11,23 +11,57 @@ import java.awt.mod.*; public class Clipboard extends Object { + private final Activity mActivity; + public Clipboard() { + mActivity = ModdingKit.getCurrentActivity(); + } + public synchronized void setContents(final Transferable contents, ClipboardOwner owner) { try { - final Activity act = ModdingKit.getCurrentActivity(); - act.runOnUiThread(new Runnable(){ + mActivity.runOnUiThread(new Runnable(){ @Override public void run() { - ClipboardManager clipboard = (ClipboardManager) act.getSystemService(Context.CLIPBOARD_SERVICE); - ClipData clip = ClipData.newPlainText("Copied text", ((StringSelection) contents).getString()); + ClipboardManager clipboard = (ClipboardManager) mActivity.getSystemService(Context.CLIPBOARD_SERVICE); + ClipData clip = ClipData.newPlainText("Minecraft", ((StringSelection) contents).getString()); clipboard.setPrimaryClip(clip); - Toast.makeText(act, "Copied to clipboard!", Toast.LENGTH_SHORT).show(); + Toast.makeText(mActivity, "Copied to clipboard!", Toast.LENGTH_SHORT).show(); } }); } catch (Exception e) { e.printStackTrace(); } } + + private Transferable clipboardText; + private boolean clipboardPasted = false; + public synchronized Transferable getContents(Object requestor) { + try { + clipboardPasted = false; + + mActivity.runOnUiThread(new Runnable(){ + + @Override + public void run() + { + ClipboardManager clipboard = (ClipboardManager) mActivity.getSystemService(Context.CLIPBOARD_SERVICE); + clipboardText = new StringSelection(clipboard.getText().toString()); + clipboardPasted = true; + Toast.makeText(mActivity, "Paste from clipboard", Toast.LENGTH_SHORT).show(); + } + }); + + while (!clipboardPasted) { + Thread.sleep(100); + } + + return clipboardText; + } catch (Exception e) { + e.printStackTrace(); + } + + return null; + } } diff --git a/app/src/main/java/java/awt/event/AWTEventListener.java b/app/src/main/java/java/awt/event/AWTEventListener.java new file mode 100644 index 000000000..76293b3a7 --- /dev/null +++ b/app/src/main/java/java/awt/event/AWTEventListener.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.awt.AWTEvent; +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface AWTEventListener extends EventListener { + + public void eventDispatched(AWTEvent event); + +} diff --git a/app/src/main/java/java/awt/event/AWTEventListenerProxy.java b/app/src/main/java/java/awt/event/AWTEventListenerProxy.java new file mode 100644 index 000000000..3edc41f3e --- /dev/null +++ b/app/src/main/java/java/awt/event/AWTEventListenerProxy.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.awt.AWTEvent; + +import java.util.EventListenerProxy; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public class AWTEventListenerProxy extends EventListenerProxy implements AWTEventListener { + + private AWTEventListener listener; + private long eventMask; + + public AWTEventListenerProxy(long eventMask, AWTEventListener listener) { + super(listener); + + // awt.193=Listener can't be zero + assert listener != null : Messages.getString("awt.193"); //$NON-NLS-1$ + + this.listener = listener; + this.eventMask = eventMask; + } + + public void eventDispatched(AWTEvent evt) { + listener.eventDispatched(evt); + } + + public long getEventMask() { + return eventMask; + } + +} diff --git a/app/src/main/java/java/awt/event/ActionEvent.java b/app/src/main/java/java/awt/event/ActionEvent.java new file mode 100644 index 000000000..e882e0db9 --- /dev/null +++ b/app/src/main/java/java/awt/event/ActionEvent.java @@ -0,0 +1,114 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.awt.AWTEvent; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public class ActionEvent extends AWTEvent { + + private static final long serialVersionUID = -7671078796273832149L; + + public static final int SHIFT_MASK = 1; + + public static final int CTRL_MASK = 2; + + public static final int META_MASK = 4; + + public static final int ALT_MASK = 8; + + public static final int ACTION_FIRST = 1001; + + public static final int ACTION_LAST = 1001; + + public static final int ACTION_PERFORMED = 1001; + + private long when; + private int modifiers; + private String command; + + public ActionEvent(Object source, int id, String command) { + this(source, id, command, 0); + } + + public ActionEvent(Object source, int id, String command, int modifiers) { + this(source, id, command, 0l, modifiers); + } + + public ActionEvent(Object source, int id, String command, long when, int modifiers) { + super(source, id); + + this.command = command; + this.when = when; + this.modifiers = modifiers; + } + + public int getModifiers() { + return modifiers; + } + + public String getActionCommand() { + return command; + } + + public long getWhen() { + return when; + } + + @Override + public String paramString() { + /* The format is based on 1.5 release behavior + * which can be revealed by the following code: + * + * ActionEvent e = new ActionEvent(new Component(){}, + * ActionEvent.ACTION_PERFORMED, "Command", + * ActionEvent.SHIFT_MASK|ActionEvent.CTRL_MASK| + * ActionEvent.META_MASK|ActionEvent.ALT_MASK); + * System.out.println(e); + */ + + String idString = (id == ACTION_PERFORMED) ? + "ACTION_PERFORMED" : "unknown type"; //$NON-NLS-1$ //$NON-NLS-2$ + String modifiersString = ""; //$NON-NLS-1$ + + if ((modifiers & SHIFT_MASK) > 0) { + modifiersString += "Shift"; //$NON-NLS-1$ + } + if ((modifiers & CTRL_MASK) > 0) { + modifiersString += modifiersString.length() == 0 ? "Ctrl" : "+Ctrl"; //$NON-NLS-1$ //$NON-NLS-2$ + } + if ((modifiers & META_MASK) > 0) { + modifiersString += modifiersString.length() == 0 ? "Meta" : "+Meta"; //$NON-NLS-1$ //$NON-NLS-2$ + } + if ((modifiers & ALT_MASK) > 0) { + modifiersString += modifiersString.length() == 0 ? "Alt" : "+Alt"; //$NON-NLS-1$ //$NON-NLS-2$ + } + + return (idString + ",cmd=" + command + ",when=" + when + //$NON-NLS-1$ //$NON-NLS-2$ + ",modifiers=" + modifiersString); //$NON-NLS-1$ + } + +} diff --git a/app/src/main/java/java/awt/event/ActionListener.java b/app/src/main/java/java/awt/event/ActionListener.java new file mode 100644 index 000000000..a6eee7a16 --- /dev/null +++ b/app/src/main/java/java/awt/event/ActionListener.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface ActionListener extends EventListener { + + public void actionPerformed(ActionEvent e); + +} diff --git a/app/src/main/java/java/awt/event/AdjustmentEvent.java b/app/src/main/java/java/awt/event/AdjustmentEvent.java new file mode 100644 index 000000000..be2d6c4ba --- /dev/null +++ b/app/src/main/java/java/awt/event/AdjustmentEvent.java @@ -0,0 +1,123 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.awt.AWTEvent; +import java.awt.Adjustable; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public class AdjustmentEvent extends AWTEvent { + + private static final long serialVersionUID = 5700290645205279921L; + + public static final int ADJUSTMENT_FIRST = 601; + + public static final int ADJUSTMENT_LAST = 601; + + public static final int ADJUSTMENT_VALUE_CHANGED = 601; + + public static final int UNIT_INCREMENT = 1; + + public static final int UNIT_DECREMENT = 2; + + public static final int BLOCK_DECREMENT = 3; + + public static final int BLOCK_INCREMENT = 4; + + public static final int TRACK = 5; + + private int type; + private int value; + private boolean isAdjusting; + + public AdjustmentEvent(Adjustable source, int id, int type, int value) { + this(source, id, type, value, false); + } + + public AdjustmentEvent(Adjustable source, int id, int type, int value, + boolean isAdjusting) { + super(source, id); + this.type = type; + this.value = value; + this.isAdjusting = isAdjusting; + } + + public int getValue() { + return value; + } + + public int getAdjustmentType() { + return type; + } + + public boolean getValueIsAdjusting() { + return isAdjusting; + } + + public Adjustable getAdjustable() { + return (Adjustable) source; + } + + @Override + public String paramString() { + /* The format is based on 1.5 release behavior + * which can be revealed by the following code: + * + * AdjustmentEvent e = new AdjustmentEvent(new Scrollbar(), + * AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED, + * AdjustmentEvent.UNIT_INCREMENT, 1); + * System.out.println(e); + */ + + String idString = (id == ADJUSTMENT_VALUE_CHANGED ? + "ADJUSTMENT_VALUE_CHANGED" : "unknown type"); //$NON-NLS-1$ //$NON-NLS-2$ + String adjType = null; + + switch (type) { + case UNIT_INCREMENT: + adjType = "UNIT_INCREMENT"; //$NON-NLS-1$ + break; + case UNIT_DECREMENT: + adjType = "UNIT_DECREMENT"; //$NON-NLS-1$ + break; + case BLOCK_INCREMENT: + adjType = "BLOCK_INCREMENT"; //$NON-NLS-1$ + break; + case BLOCK_DECREMENT: + adjType = "BLOCK_DECREMENT"; //$NON-NLS-1$ + break; + case TRACK: + adjType = "TRACK"; //$NON-NLS-1$ + break; + default: + adjType = "unknown type"; //$NON-NLS-1$ + } + + return (idString + ",adjType=" + adjType + ",value=" + value + //$NON-NLS-1$ //$NON-NLS-2$ + ",isAdjusting=" + isAdjusting); //$NON-NLS-1$ + } + +} diff --git a/app/src/main/java/java/awt/event/AdjustmentListener.java b/app/src/main/java/java/awt/event/AdjustmentListener.java new file mode 100644 index 000000000..5f6a72473 --- /dev/null +++ b/app/src/main/java/java/awt/event/AdjustmentListener.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface AdjustmentListener extends EventListener { + + public void adjustmentValueChanged(AdjustmentEvent e); + +} diff --git a/app/src/main/java/java/awt/event/ComponentAdapter.java b/app/src/main/java/java/awt/event/ComponentAdapter.java new file mode 100644 index 000000000..c42235f96 --- /dev/null +++ b/app/src/main/java/java/awt/event/ComponentAdapter.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public abstract class ComponentAdapter implements ComponentListener { + + public ComponentAdapter() { + } + + public void componentHidden(ComponentEvent e) { + } + + public void componentMoved(ComponentEvent e) { + } + + public void componentResized(ComponentEvent e) { + } + + public void componentShown(ComponentEvent e) { + } + +} diff --git a/app/src/main/java/java/awt/event/ComponentEvent.java b/app/src/main/java/java/awt/event/ComponentEvent.java new file mode 100644 index 000000000..760d3abf2 --- /dev/null +++ b/app/src/main/java/java/awt/event/ComponentEvent.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.awt.AWTEvent; +import java.awt.Component; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public class ComponentEvent extends AWTEvent { + + private static final long serialVersionUID = 8101406823902992965L; + + public static final int COMPONENT_FIRST = 100; + + public static final int COMPONENT_LAST = 103; + + public static final int COMPONENT_MOVED = 100; + + public static final int COMPONENT_RESIZED = 101; + + public static final int COMPONENT_SHOWN = 102; + + public static final int COMPONENT_HIDDEN = 103; + + public ComponentEvent(Component source, int id) { + super(source, id); + } + + public Component getComponent() { + return (Component) source; + } + + @Override + public String paramString() { + /* The format is based on 1.5 release behavior + * which can be revealed by the following code: + * + * ComponentEvent e = new ComponentEvent(new Button("Button"), + * ComponentEvent.COMPONENT_SHOWN); + * System.out.println(e); + */ + + String idString = null; + Component c = getComponent(); + + switch (id) { + case COMPONENT_MOVED: + idString = "COMPONENT_MOVED"; //$NON-NLS-1$ + break; + case COMPONENT_RESIZED: + idString = "COMPONENT_RESIZED"; //$NON-NLS-1$ + break; + case COMPONENT_SHOWN: + return "COMPONENT_SHOWN"; //$NON-NLS-1$ + case COMPONENT_HIDDEN: + return "COMPONENT_HIDDEN"; //$NON-NLS-1$ + default: + return "unknown type"; //$NON-NLS-1$ + } + + return (idString + " (" + c.getX() + "," + c.getY() + //$NON-NLS-1$ //$NON-NLS-2$ + " " + c.getWidth()+ "x" + c.getHeight() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + +} diff --git a/app/src/main/java/java/awt/event/ComponentListener.java b/app/src/main/java/java/awt/event/ComponentListener.java new file mode 100644 index 000000000..a5adba2e9 --- /dev/null +++ b/app/src/main/java/java/awt/event/ComponentListener.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface ComponentListener extends EventListener { + + public void componentHidden(ComponentEvent e); + + public void componentMoved(ComponentEvent e); + + public void componentResized(ComponentEvent e); + + public void componentShown(ComponentEvent e); + +} diff --git a/app/src/main/java/java/awt/event/ContainerAdapter.java b/app/src/main/java/java/awt/event/ContainerAdapter.java new file mode 100644 index 000000000..44983c793 --- /dev/null +++ b/app/src/main/java/java/awt/event/ContainerAdapter.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public abstract class ContainerAdapter implements ContainerListener { + + public ContainerAdapter() { + } + + public void componentAdded(ContainerEvent e) { + } + + public void componentRemoved(ContainerEvent e) { + } + +} diff --git a/app/src/main/java/java/awt/event/ContainerEvent.java b/app/src/main/java/java/awt/event/ContainerEvent.java new file mode 100644 index 000000000..372c9e477 --- /dev/null +++ b/app/src/main/java/java/awt/event/ContainerEvent.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.awt.Component; +//???AWT: import java.awt.Container; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public class ContainerEvent extends ComponentEvent { + + private static final long serialVersionUID = -4114942250539772041L; + + public static final int CONTAINER_FIRST = 300; + + public static final int CONTAINER_LAST = 301; + + public static final int COMPONENT_ADDED = 300; + + public static final int COMPONENT_REMOVED = 301; + + private Component child; + + public ContainerEvent(Component src, int id, Component child) { + super(src, id); + this.child = child; + } + + public Component getChild() { + return child; + } + + //???AWT + /* + public Container getContainer() { + return (Container) source; + } + */ + + @Override + public String paramString() { + /* The format is based on 1.5 release behavior + * which can be revealed by the following code: + * + * ContainerEvent e = new ContainerEvent(new Panel(), + * ContainerEvent.COMPONENT_ADDED, + * new Button("Button")); + * System.out.println(e); + */ + + String idString = null; + + switch (id) { + case COMPONENT_ADDED: + idString = "COMPONENT_ADDED"; //$NON-NLS-1$ + break; + case COMPONENT_REMOVED: + idString = "COMPONENT_REMOVED"; //$NON-NLS-1$ + break; + default: + idString = "unknown type"; //$NON-NLS-1$ + } + + return (idString + ",child=" + child.getName()); //$NON-NLS-1$ + } + +} diff --git a/app/src/main/java/java/awt/event/ContainerListener.java b/app/src/main/java/java/awt/event/ContainerListener.java new file mode 100644 index 000000000..517859e43 --- /dev/null +++ b/app/src/main/java/java/awt/event/ContainerListener.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface ContainerListener extends EventListener { + + public void componentAdded(ContainerEvent e); + + public void componentRemoved(ContainerEvent e); + +} diff --git a/app/src/main/java/java/awt/event/FocusAdapter.java b/app/src/main/java/java/awt/event/FocusAdapter.java new file mode 100644 index 000000000..3a3e37fb0 --- /dev/null +++ b/app/src/main/java/java/awt/event/FocusAdapter.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public abstract class FocusAdapter implements FocusListener { + + public FocusAdapter() { + } + + public void focusGained(FocusEvent e) { + } + + public void focusLost(FocusEvent e) { + } + +} diff --git a/app/src/main/java/java/awt/event/FocusEvent.java b/app/src/main/java/java/awt/event/FocusEvent.java new file mode 100644 index 000000000..4a1868957 --- /dev/null +++ b/app/src/main/java/java/awt/event/FocusEvent.java @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.awt.Component; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public class FocusEvent extends ComponentEvent { + + private static final long serialVersionUID = 523753786457416396L; + + public static final int FOCUS_FIRST = 1004; + + public static final int FOCUS_LAST = 1005; + + public static final int FOCUS_GAINED = 1004; + + public static final int FOCUS_LOST = 1005; + + private boolean temporary; + private Component opposite; + + public FocusEvent(Component source, int id) { + this(source, id, false); + } + + public FocusEvent(Component source, int id, boolean temporary) { + this(source, id, temporary, null); + } + + public FocusEvent(Component source, int id, boolean temporary, Component opposite) { + super(source, id); + this.temporary = temporary; + this.opposite = opposite; + } + + public Component getOppositeComponent() { + return opposite; + } + + public boolean isTemporary() { + return temporary; + } + + @Override + public String paramString() { + /* The format is based on 1.5 release behavior + * which can be revealed by the following code: + * + * FocusEvent e = new FocusEvent(new Button("Button0"), + * FocusEvent.FOCUS_GAINED, false, new Button("Button1")); + * System.out.println(e); + */ + + String idString = null; + + switch (id) { + case FOCUS_GAINED: + idString = "FOCUS_GAINED"; //$NON-NLS-1$ + break; + case FOCUS_LOST: + idString = "FOCUS_LOST"; //$NON-NLS-1$ + break; + default: + idString = "unknown type"; //$NON-NLS-1$ + } + + return (idString + + (temporary ? ",temporary" : ",permanent") + //$NON-NLS-1$ //$NON-NLS-2$ + ",opposite=" + opposite); //$NON-NLS-1$ + } + +} diff --git a/app/src/main/java/java/awt/event/FocusListener.java b/app/src/main/java/java/awt/event/FocusListener.java new file mode 100644 index 000000000..6bbbd001f --- /dev/null +++ b/app/src/main/java/java/awt/event/FocusListener.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface FocusListener extends EventListener { + + public void focusGained(FocusEvent e); + + public void focusLost(FocusEvent e); + +} diff --git a/app/src/main/java/java/awt/event/HierarchyBoundsAdapter.java b/app/src/main/java/java/awt/event/HierarchyBoundsAdapter.java new file mode 100644 index 000000000..bbfe8ff2d --- /dev/null +++ b/app/src/main/java/java/awt/event/HierarchyBoundsAdapter.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public abstract class HierarchyBoundsAdapter implements HierarchyBoundsListener { + + public HierarchyBoundsAdapter() { + } + + public void ancestorMoved(HierarchyEvent e) { + } + + public void ancestorResized(HierarchyEvent e) { + } + +} diff --git a/app/src/main/java/java/awt/event/HierarchyBoundsListener.java b/app/src/main/java/java/awt/event/HierarchyBoundsListener.java new file mode 100644 index 000000000..3e8f2e790 --- /dev/null +++ b/app/src/main/java/java/awt/event/HierarchyBoundsListener.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface HierarchyBoundsListener extends EventListener { + + public void ancestorMoved(HierarchyEvent e); + + public void ancestorResized(HierarchyEvent e); + +} diff --git a/app/src/main/java/java/awt/event/HierarchyEvent.java b/app/src/main/java/java/awt/event/HierarchyEvent.java new file mode 100644 index 000000000..c1d22f44c --- /dev/null +++ b/app/src/main/java/java/awt/event/HierarchyEvent.java @@ -0,0 +1,154 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.awt.AWTEvent; +import java.awt.Component; +//???AWT: import java.awt.Container; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public class HierarchyEvent extends AWTEvent { + + private static final long serialVersionUID = -5337576970038043990L; + + public static final int HIERARCHY_FIRST = 1400; + + public static final int HIERARCHY_CHANGED = 1400; + + public static final int ANCESTOR_MOVED = 1401; + + public static final int ANCESTOR_RESIZED = 1402; + + public static final int HIERARCHY_LAST = 1402; + + public static final int PARENT_CHANGED = 1; + + public static final int DISPLAYABILITY_CHANGED = 2; + + public static final int SHOWING_CHANGED = 4; + + //???AWT: private Container changedParent; + private Component changed; + private long changeFlag; + + //???AWT + /* + public HierarchyEvent(Component source, int id, Component changed, + Container changedParent) { + this(source, id, changed, changedParent, 0l); + } + */ + + //???AWT + /* + public HierarchyEvent(Component source, int id, Component changed, + Container changedParent, long changeFlags) { + super(source, id); + + this.changed = changed; + this.changedParent = changedParent; + this.changeFlag = changeFlags; + } + */ + //???AWT: Fake constructor, should be as above. + public HierarchyEvent(Component source, int id, Component changed, + Object changedParent, long changeFlags) { + super(source, id); + +// this.changed = changed; +// this.changedParent = changedParent; +// this.changeFlag = changeFlags; + } + + public Component getComponent() { + return (Component) source; + } + + public long getChangeFlags() { + return changeFlag; + } + + public Component getChanged() { + return changed; + } + + //???AWT + /* + public Container getChangedParent() { + return changedParent; + + } + */ + + @Override + public String paramString() { + /* The format is based on 1.5 release behavior + * which can be revealed by the following code: + * + * HierarchyEvent e = new HierarchyEvent(new Button("Button"), + * HierarchyEvent.HIERARCHY_CHANGED, + * new Panel(), new Container()); + * System.out.println(e); + */ + String paramString = null; + + switch (id) { + case HIERARCHY_CHANGED: + paramString = "HIERARCHY_CHANGED"; //$NON-NLS-1$ + break; + case ANCESTOR_MOVED: + paramString = "ANCESTOR_MOVED"; //$NON-NLS-1$ + break; + case ANCESTOR_RESIZED: + paramString = "ANCESTOR_RESIZED"; //$NON-NLS-1$ + break; + default: + paramString = "unknown type"; //$NON-NLS-1$ + } + + paramString += " ("; //$NON-NLS-1$ + + if (id == HIERARCHY_CHANGED) { + if ((changeFlag & PARENT_CHANGED) > 0) { + paramString += "PARENT_CHANGED,"; //$NON-NLS-1$ + } + if ((changeFlag & DISPLAYABILITY_CHANGED) > 0) { + paramString += "DISPLAYABILITY_CHANGED,"; //$NON-NLS-1$ + } + if ((changeFlag & SHOWING_CHANGED) > 0) { + paramString += "SHOWING_CHANGED,"; //$NON-NLS-1$ + } + } + + //???AWT + /* + return paramString + "changed=" + changed + //$NON-NLS-1$ + ",changedParent=" + changedParent + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + */ + return paramString; + } + +} diff --git a/app/src/main/java/java/awt/event/HierarchyListener.java b/app/src/main/java/java/awt/event/HierarchyListener.java new file mode 100644 index 000000000..ff3d9bcfc --- /dev/null +++ b/app/src/main/java/java/awt/event/HierarchyListener.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface HierarchyListener extends EventListener { + + public void hierarchyChanged(HierarchyEvent e); + +} diff --git a/app/src/main/java/java/awt/event/InputEvent.java b/app/src/main/java/java/awt/event/InputEvent.java new file mode 100644 index 000000000..343b7a3b0 --- /dev/null +++ b/app/src/main/java/java/awt/event/InputEvent.java @@ -0,0 +1,190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.awt.Component; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public abstract class InputEvent extends ComponentEvent { + + private static final long serialVersionUID = -2482525981698309786L; + + public static final int SHIFT_MASK = 1; + + public static final int CTRL_MASK = 2; + + public static final int META_MASK = 4; + + public static final int ALT_MASK = 8; + + public static final int ALT_GRAPH_MASK = 32; + + public static final int BUTTON1_MASK = 16; + + public static final int BUTTON2_MASK = 8; + + public static final int BUTTON3_MASK = 4; + + public static final int SHIFT_DOWN_MASK = 64; + + public static final int CTRL_DOWN_MASK = 128; + + public static final int META_DOWN_MASK = 256; + + public static final int ALT_DOWN_MASK = 512; + + public static final int BUTTON1_DOWN_MASK = 1024; + + public static final int BUTTON2_DOWN_MASK = 2048; + + public static final int BUTTON3_DOWN_MASK = 4096; + + public static final int ALT_GRAPH_DOWN_MASK = 8192; + + private static final int DOWN_MASKS = SHIFT_DOWN_MASK | CTRL_DOWN_MASK | + META_DOWN_MASK | ALT_DOWN_MASK | BUTTON1_DOWN_MASK | + BUTTON2_DOWN_MASK | BUTTON3_DOWN_MASK | ALT_GRAPH_DOWN_MASK; + + private long when; + private int modifiersEx; + + public static String getModifiersExText(int modifiers/*Ex*/) { + return MouseEvent.addMouseModifiersExText( + KeyEvent.getKeyModifiersExText(modifiers), modifiers); + } + + static int extractExFlags(int modifiers) { + int exFlags = modifiers & DOWN_MASKS; + + if ((modifiers & SHIFT_MASK) != 0) { + exFlags |= SHIFT_DOWN_MASK; + } + if ((modifiers & CTRL_MASK) != 0) { + exFlags |= CTRL_DOWN_MASK; + } + if ((modifiers & META_MASK) != 0) { + exFlags |= META_DOWN_MASK; + } + if ((modifiers & ALT_MASK) != 0) { + exFlags |= ALT_DOWN_MASK; + } + if ((modifiers & ALT_GRAPH_MASK) != 0) { + exFlags |= ALT_GRAPH_DOWN_MASK; + } + if ((modifiers & BUTTON1_MASK) != 0) { + exFlags |= BUTTON1_DOWN_MASK; + } + if ((modifiers & BUTTON2_MASK) != 0) { + exFlags |= BUTTON2_DOWN_MASK; + } + if ((modifiers & BUTTON3_MASK) != 0) { + exFlags |= BUTTON3_DOWN_MASK; + } + + return exFlags; + } + + InputEvent(Component source, int id, long when, int modifiers) { + super(source, id); + + this.when = when; + modifiersEx = extractExFlags(modifiers); + } + + public int getModifiers() { + int modifiers = 0; + + if ((modifiersEx & SHIFT_DOWN_MASK) != 0) { + modifiers |= SHIFT_MASK; + } + if ((modifiersEx & CTRL_DOWN_MASK) != 0) { + modifiers |= CTRL_MASK; + } + if ((modifiersEx & META_DOWN_MASK) != 0) { + modifiers |= META_MASK; + } + if ((modifiersEx & ALT_DOWN_MASK) != 0) { + modifiers |= ALT_MASK; + } + if ((modifiersEx & ALT_GRAPH_DOWN_MASK) != 0) { + modifiers |= ALT_GRAPH_MASK; + } + if ((modifiersEx & BUTTON1_DOWN_MASK) != 0) { + modifiers |= BUTTON1_MASK; + } + if ((modifiersEx & BUTTON2_DOWN_MASK) != 0) { + modifiers |= BUTTON2_MASK; + } + if ((modifiersEx & BUTTON3_DOWN_MASK) != 0) { + modifiers |= BUTTON3_MASK; + } + + return modifiers; + } + + public int getModifiersEx() { + return modifiersEx; + } + + void setModifiers(int modifiers) { + modifiersEx = extractExFlags(modifiers); + } + + public boolean isAltDown() { + return ((modifiersEx & ALT_DOWN_MASK) != 0); + } + + public boolean isAltGraphDown() { + return ((modifiersEx & ALT_GRAPH_DOWN_MASK) != 0); + } + + public boolean isControlDown() { + return ((modifiersEx & CTRL_DOWN_MASK) != 0); + } + + public boolean isMetaDown() { + return ((modifiersEx & META_DOWN_MASK) != 0); + } + + public boolean isShiftDown() { + return ((modifiersEx & SHIFT_DOWN_MASK) != 0); + } + + public long getWhen() { + return when; + } + + @Override + public void consume() { + super.consume(); + } + + @Override + public boolean isConsumed() { + return super.isConsumed(); + } + +} diff --git a/app/src/main/java/java/awt/event/InputMethodEvent.java b/app/src/main/java/java/awt/event/InputMethodEvent.java new file mode 100644 index 000000000..be001a580 --- /dev/null +++ b/app/src/main/java/java/awt/event/InputMethodEvent.java @@ -0,0 +1,156 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.awt.AWTEvent; +import java.awt.Component; +import java.awt.font.TextHitInfo; +import java.text.AttributedCharacterIterator; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public class InputMethodEvent extends AWTEvent { + + private static final long serialVersionUID = 4727190874778922661L; + + public static final int INPUT_METHOD_FIRST = 1100; + + public static final int INPUT_METHOD_TEXT_CHANGED = 1100; + + public static final int CARET_POSITION_CHANGED = 1101; + + public static final int INPUT_METHOD_LAST = 1101; + + private AttributedCharacterIterator text; + private TextHitInfo visiblePosition; + private TextHitInfo caret; + private int committedCharacterCount; + private long when; + + public InputMethodEvent(Component src, int id, + TextHitInfo caret, + TextHitInfo visiblePos) { + this(src, id, null, 0, caret, visiblePos); + } + + public InputMethodEvent(Component src, int id, + AttributedCharacterIterator text, + int commitedCharCount, + TextHitInfo caret, + TextHitInfo visiblePos) { + this(src, id, 0l, text, commitedCharCount, caret, visiblePos); + } + + public InputMethodEvent(Component src, int id, long when, + AttributedCharacterIterator text, + int committedCharacterCount, + TextHitInfo caret, + TextHitInfo visiblePos) { + super(src, id); + + if ((id < INPUT_METHOD_FIRST) || (id > INPUT_METHOD_LAST)) { + // awt.18E=Wrong event id + throw new IllegalArgumentException(Messages.getString("awt.18E")); //$NON-NLS-1$ + } + if ((id == CARET_POSITION_CHANGED) && (text != null)) { + // awt.18F=Text must be null for CARET_POSITION_CHANGED + throw new IllegalArgumentException(Messages.getString("awt.18F")); //$NON-NLS-1$ + } + if ((text != null) && + ((committedCharacterCount < 0) || + (committedCharacterCount > + (text.getEndIndex() - text.getBeginIndex())))) { + // awt.190=Wrong committedCharacterCount + throw new IllegalArgumentException(Messages.getString("awt.190")); //$NON-NLS-1$ + } + + this.when = when; + this.text = text; + this.caret = caret; + this.visiblePosition = visiblePos; + this.committedCharacterCount = committedCharacterCount; + } + + public TextHitInfo getCaret() { + return caret; + } + + public int getCommittedCharacterCount() { + return committedCharacterCount; + } + + public AttributedCharacterIterator getText() { + return text; + } + + public TextHitInfo getVisiblePosition() { + return visiblePosition; + } + + public long getWhen() { + return when; + } + + @Override + public void consume() { + super.consume(); + } + + @Override + public boolean isConsumed() { + return super.isConsumed(); + } + + @Override + public String paramString() { + /* The format is based on 1.5 release behavior + * which can be revealed by the following code: + * + * InputMethodEvent e = new InputMethodEvent(new Component(){}, + * InputMethodEvent.INPUT_METHOD_TEXT_CHANGED, + * TextHitInfo.leading(1), TextHitInfo.trailing(2)); + * System.out.println(e); + */ + String typeString = null; + + switch (id) { + case INPUT_METHOD_TEXT_CHANGED: + typeString = "INPUT_METHOD_TEXT_CHANGED"; //$NON-NLS-1$ + break; + case CARET_POSITION_CHANGED: + typeString = "CARET_POSITION_CHANGED"; //$NON-NLS-1$ + break; + default: + typeString = "unknown type"; //$NON-NLS-1$ + } + + return typeString + ",text=" + text + //$NON-NLS-1$ + ",commitedCharCount=" + committedCharacterCount + //$NON-NLS-1$ + ",caret=" + caret + ",visiblePosition=" + visiblePosition; //$NON-NLS-1$ //$NON-NLS-2$ + } + +} diff --git a/app/src/main/java/java/awt/event/InputMethodListener.java b/app/src/main/java/java/awt/event/InputMethodListener.java new file mode 100644 index 000000000..85eaa7e6c --- /dev/null +++ b/app/src/main/java/java/awt/event/InputMethodListener.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface InputMethodListener extends EventListener { + + public void caretPositionChanged(InputMethodEvent e); + + public void inputMethodTextChanged(InputMethodEvent e); + +} diff --git a/app/src/main/java/java/awt/event/InvocationEvent.java b/app/src/main/java/java/awt/event/InvocationEvent.java new file mode 100644 index 000000000..58e3b7298 --- /dev/null +++ b/app/src/main/java/java/awt/event/InvocationEvent.java @@ -0,0 +1,138 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.awt.AWTEvent; +import java.awt.ActiveEvent; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public class InvocationEvent extends AWTEvent implements ActiveEvent { + + private static final long serialVersionUID = 436056344909459450L; + + public static final int INVOCATION_FIRST = 1200; + + public static final int INVOCATION_DEFAULT = 1200; + + public static final int INVOCATION_LAST = 1200; + + protected Runnable runnable; + + protected Object notifier; + + protected boolean catchExceptions; + + private long when; + private Throwable throwable; + + public InvocationEvent(Object source, Runnable runnable) { + this(source, runnable, null, false); + } + + public InvocationEvent(Object source, Runnable runnable, + Object notifier, boolean catchExceptions) { + this(source, INVOCATION_DEFAULT, runnable, notifier, catchExceptions); + } + + protected InvocationEvent(Object source, int id, Runnable runnable, + Object notifier, boolean catchExceptions) + { + super(source, id); + + // awt.18C=Cannot invoke null runnable + assert runnable != null : Messages.getString("awt.18C"); //$NON-NLS-1$ + + if (source == null) { + // awt.18D=Source is null + throw new IllegalArgumentException(Messages.getString("awt.18D")); //$NON-NLS-1$ + } + this.runnable = runnable; + this.notifier = notifier; + this.catchExceptions = catchExceptions; + + throwable = null; + when = System.currentTimeMillis(); + } + + public void dispatch() { + if (!catchExceptions) { + runAndNotify(); + } else { + try { + runAndNotify(); + } catch (Throwable t) { + throwable = t; + } + } + } + + private void runAndNotify() { + if (notifier != null) { + synchronized(notifier) { + try { + runnable.run(); + } finally { + notifier.notifyAll(); + } + } + } else { + runnable.run(); + } + } + + public Exception getException() { + return (throwable != null && throwable instanceof Exception) ? + (Exception)throwable : null; + } + + public Throwable getThrowable() { + return throwable; + } + + public long getWhen() { + return when; + } + + @Override + public String paramString() { + /* The format is based on 1.5 release behavior + * which can be revealed by the following code: + * + * InvocationEvent e = new InvocationEvent(new Component(){}, + * new Runnable() { public void run(){} }); + * System.out.println(e); + */ + + return ((id == INVOCATION_DEFAULT ? "INVOCATION_DEFAULT" : "unknown type") + //$NON-NLS-1$ //$NON-NLS-2$ + ",runnable=" + runnable + //$NON-NLS-1$ + ",notifier=" + notifier + //$NON-NLS-1$ + ",catchExceptions=" + catchExceptions + //$NON-NLS-1$ + ",when=" + when); //$NON-NLS-1$ + } + +} diff --git a/app/src/main/java/java/awt/event/ItemEvent.java b/app/src/main/java/java/awt/event/ItemEvent.java new file mode 100644 index 000000000..09908f24f --- /dev/null +++ b/app/src/main/java/java/awt/event/ItemEvent.java @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.awt.AWTEvent; +import java.awt.ItemSelectable; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public class ItemEvent extends AWTEvent { + + private static final long serialVersionUID = -608708132447206933L; + + public static final int ITEM_FIRST = 701; + + public static final int ITEM_LAST = 701; + + public static final int ITEM_STATE_CHANGED = 701; + + public static final int SELECTED = 1; + + public static final int DESELECTED = 2; + + private Object item; + private int stateChange; + + public ItemEvent(ItemSelectable source, int id, Object item, int stateChange) { + super(source, id); + + this.item = item; + this.stateChange = stateChange; + } + + public Object getItem() { + return item; + } + + public int getStateChange() { + return stateChange; + } + + public ItemSelectable getItemSelectable() { + return (ItemSelectable) source; + } + + @Override + public String paramString() { + /* The format is based on 1.5 release behavior + * which can be revealed by the following code: + * + * Checkbox c = new Checkbox("Checkbox", true); + * ItemEvent e = new ItemEvent(c, ItemEvent.ITEM_STATE_CHANGED, + * c, ItemEvent.SELECTED); + * System.out.println(e); + */ + + String stateString = null; + + switch (stateChange) { + case SELECTED: + stateString = "SELECTED"; //$NON-NLS-1$ + break; + case DESELECTED: + stateString = "DESELECTED"; //$NON-NLS-1$ + break; + default: + stateString = "unknown type"; //$NON-NLS-1$ + } + + return ((id == ITEM_STATE_CHANGED ? "ITEM_STATE_CHANGED" : "unknown type") + //$NON-NLS-1$ //$NON-NLS-2$ + ",item=" + item + ",stateChange=" + stateString); //$NON-NLS-1$ //$NON-NLS-2$ + } + +} diff --git a/app/src/main/java/java/awt/event/ItemListener.java b/app/src/main/java/java/awt/event/ItemListener.java new file mode 100644 index 000000000..8dec67322 --- /dev/null +++ b/app/src/main/java/java/awt/event/ItemListener.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface ItemListener extends EventListener { + + public void itemStateChanged(ItemEvent e); + +} diff --git a/app/src/main/java/java/awt/event/KeyAdapter.java b/app/src/main/java/java/awt/event/KeyAdapter.java new file mode 100644 index 000000000..a96cca8d8 --- /dev/null +++ b/app/src/main/java/java/awt/event/KeyAdapter.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public abstract class KeyAdapter implements KeyListener { + + public KeyAdapter() { + } + + public void keyPressed(KeyEvent e) { + } + + public void keyReleased(KeyEvent e) { + } + + public void keyTyped(KeyEvent e) { + } + +} diff --git a/app/src/main/java/java/awt/event/KeyEvent.java b/app/src/main/java/java/awt/event/KeyEvent.java new file mode 100644 index 000000000..8627f708d --- /dev/null +++ b/app/src/main/java/java/awt/event/KeyEvent.java @@ -0,0 +1,687 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.awt.Component; +import java.awt.Toolkit; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public class KeyEvent extends InputEvent { + + private static final long serialVersionUID = -2352130953028126954L; + + public static final int KEY_FIRST = 400; + + public static final int KEY_LAST = 402; + + public static final int KEY_TYPED = 400; + + public static final int KEY_PRESSED = 401; + + public static final int KEY_RELEASED = 402; + + public static final int VK_ENTER = 10; + + public static final int VK_BACK_SPACE = 8; + + public static final int VK_TAB = 9; + + public static final int VK_CANCEL = 3; + + public static final int VK_CLEAR = 12; + + public static final int VK_SHIFT = 16; + + public static final int VK_CONTROL = 17; + + public static final int VK_ALT = 18; + + public static final int VK_PAUSE = 19; + + public static final int VK_CAPS_LOCK = 20; + + public static final int VK_ESCAPE = 27; + + public static final int VK_SPACE = 32; + + public static final int VK_PAGE_UP = 33; + + public static final int VK_PAGE_DOWN = 34; + + public static final int VK_END = 35; + + public static final int VK_HOME = 36; + + public static final int VK_LEFT = 37; + + public static final int VK_UP = 38; + + public static final int VK_RIGHT = 39; + + public static final int VK_DOWN = 40; + + public static final int VK_COMMA = 44; + + public static final int VK_MINUS = 45; + + public static final int VK_PERIOD = 46; + + public static final int VK_SLASH = 47; + + public static final int VK_0 = 48; + + public static final int VK_1 = 49; + + public static final int VK_2 = 50; + + public static final int VK_3 = 51; + + public static final int VK_4 = 52; + + public static final int VK_5 = 53; + + public static final int VK_6 = 54; + + public static final int VK_7 = 55; + + public static final int VK_8 = 56; + + public static final int VK_9 = 57; + + public static final int VK_SEMICOLON = 59; + + public static final int VK_EQUALS = 61; + + public static final int VK_A = 65; + + public static final int VK_B = 66; + + public static final int VK_C = 67; + + public static final int VK_D = 68; + + public static final int VK_E = 69; + + public static final int VK_F = 70; + + public static final int VK_G = 71; + + public static final int VK_H = 72; + + public static final int VK_I = 73; + + public static final int VK_J = 74; + + public static final int VK_K = 75; + + public static final int VK_L = 76; + + public static final int VK_M = 77; + + public static final int VK_N = 78; + + public static final int VK_O = 79; + + public static final int VK_P = 80; + + public static final int VK_Q = 81; + + public static final int VK_R = 82; + + public static final int VK_S = 83; + + public static final int VK_T = 84; + + public static final int VK_U = 85; + + public static final int VK_V = 86; + + public static final int VK_W = 87; + + public static final int VK_X = 88; + + public static final int VK_Y = 89; + + public static final int VK_Z = 90; + + public static final int VK_OPEN_BRACKET = 91; + + public static final int VK_BACK_SLASH = 92; + + public static final int VK_CLOSE_BRACKET = 93; + + public static final int VK_NUMPAD0 = 96; + + public static final int VK_NUMPAD1 = 97; + + public static final int VK_NUMPAD2 = 98; + + public static final int VK_NUMPAD3 = 99; + + public static final int VK_NUMPAD4 = 100; + + public static final int VK_NUMPAD5 = 101; + + public static final int VK_NUMPAD6 = 102; + + public static final int VK_NUMPAD7 = 103; + + public static final int VK_NUMPAD8 = 104; + + public static final int VK_NUMPAD9 = 105; + + public static final int VK_MULTIPLY = 106; + + public static final int VK_ADD = 107; + + public static final int VK_SEPARATER = 108; + + public static final int VK_SEPARATOR = 108; + + public static final int VK_SUBTRACT = 109; + + public static final int VK_DECIMAL = 110; + + public static final int VK_DIVIDE = 111; + + public static final int VK_DELETE = 127; + + public static final int VK_NUM_LOCK = 144; + + public static final int VK_SCROLL_LOCK = 145; + + public static final int VK_F1 = 112; + + public static final int VK_F2 = 113; + + public static final int VK_F3 = 114; + + public static final int VK_F4 = 115; + + public static final int VK_F5 = 116; + + public static final int VK_F6 = 117; + + public static final int VK_F7 = 118; + + public static final int VK_F8 = 119; + + public static final int VK_F9 = 120; + + public static final int VK_F10 = 121; + + public static final int VK_F11 = 122; + + public static final int VK_F12 = 123; + + public static final int VK_F13 = 61440; + + public static final int VK_F14 = 61441; + + public static final int VK_F15 = 61442; + + public static final int VK_F16 = 61443; + + public static final int VK_F17 = 61444; + + public static final int VK_F18 = 61445; + + public static final int VK_F19 = 61446; + + public static final int VK_F20 = 61447; + + public static final int VK_F21 = 61448; + + public static final int VK_F22 = 61449; + + public static final int VK_F23 = 61450; + + public static final int VK_F24 = 61451; + + public static final int VK_PRINTSCREEN = 154; + + public static final int VK_INSERT = 155; + + public static final int VK_HELP = 156; + + public static final int VK_META = 157; + + public static final int VK_BACK_QUOTE = 192; + + public static final int VK_QUOTE = 222; + + public static final int VK_KP_UP = 224; + + public static final int VK_KP_DOWN = 225; + + public static final int VK_KP_LEFT = 226; + + public static final int VK_KP_RIGHT = 227; + + public static final int VK_DEAD_GRAVE = 128; + + public static final int VK_DEAD_ACUTE = 129; + + public static final int VK_DEAD_CIRCUMFLEX = 130; + + public static final int VK_DEAD_TILDE = 131; + + public static final int VK_DEAD_MACRON = 132; + + public static final int VK_DEAD_BREVE = 133; + + public static final int VK_DEAD_ABOVEDOT = 134; + + public static final int VK_DEAD_DIAERESIS = 135; + + public static final int VK_DEAD_ABOVERING = 136; + + public static final int VK_DEAD_DOUBLEACUTE = 137; + + public static final int VK_DEAD_CARON = 138; + + public static final int VK_DEAD_CEDILLA = 139; + + public static final int VK_DEAD_OGONEK = 140; + + public static final int VK_DEAD_IOTA = 141; + + public static final int VK_DEAD_VOICED_SOUND = 142; + + public static final int VK_DEAD_SEMIVOICED_SOUND = 143; + + public static final int VK_AMPERSAND = 150; + + public static final int VK_ASTERISK = 151; + + public static final int VK_QUOTEDBL = 152; + + public static final int VK_LESS = 153; + + public static final int VK_GREATER = 160; + + public static final int VK_BRACELEFT = 161; + + public static final int VK_BRACERIGHT = 162; + + public static final int VK_AT = 512; + + public static final int VK_COLON = 513; + + public static final int VK_CIRCUMFLEX = 514; + + public static final int VK_DOLLAR = 515; + + public static final int VK_EURO_SIGN = 516; + + public static final int VK_EXCLAMATION_MARK = 517; + + public static final int VK_INVERTED_EXCLAMATION_MARK = 518; + + public static final int VK_LEFT_PARENTHESIS = 519; + + public static final int VK_NUMBER_SIGN = 520; + + public static final int VK_PLUS = 521; + + public static final int VK_RIGHT_PARENTHESIS = 522; + + public static final int VK_UNDERSCORE = 523; + + public static final int VK_FINAL = 24; + + public static final int VK_WINDOWS = 524; + + public static final int VK_CONTEXT_MENU = 525; + + public static final int VK_CONVERT = 28; + + public static final int VK_NONCONVERT = 29; + + public static final int VK_ACCEPT = 30; + + public static final int VK_MODECHANGE = 31; + + public static final int VK_KANA = 21; + + public static final int VK_KANJI = 25; + + public static final int VK_ALPHANUMERIC = 240; + + public static final int VK_KATAKANA = 241; + + public static final int VK_HIRAGANA = 242; + + public static final int VK_FULL_WIDTH = 243; + + public static final int VK_HALF_WIDTH = 244; + + public static final int VK_ROMAN_CHARACTERS = 245; + + public static final int VK_ALL_CANDIDATES = 256; + + public static final int VK_PREVIOUS_CANDIDATE = 257; + + public static final int VK_CODE_INPUT = 258; + + public static final int VK_JAPANESE_KATAKANA = 259; + + public static final int VK_JAPANESE_HIRAGANA = 260; + + public static final int VK_JAPANESE_ROMAN = 261; + + public static final int VK_KANA_LOCK = 262; + + public static final int VK_INPUT_METHOD_ON_OFF = 263; + + public static final int VK_CUT = 65489; + + public static final int VK_COPY = 65485; + + public static final int VK_PASTE = 65487; + + public static final int VK_UNDO = 65483; + + public static final int VK_AGAIN = 65481; + + public static final int VK_FIND = 65488; + + public static final int VK_PROPS = 65482; + + public static final int VK_STOP = 65480; + + public static final int VK_COMPOSE = 65312; + + public static final int VK_ALT_GRAPH = 65406; + + public static final int VK_BEGIN = 65368; + + public static final int VK_UNDEFINED = 0; + + public static final char CHAR_UNDEFINED = (char)(-1); + + public static final int KEY_LOCATION_UNKNOWN = 0; + + public static final int KEY_LOCATION_STANDARD = 1; + + public static final int KEY_LOCATION_LEFT = 2; + + public static final int KEY_LOCATION_RIGHT = 3; + + public static final int KEY_LOCATION_NUMPAD = 4; + + private int keyCode; + private char keyChar; + private int keyLocation; + + public static String getKeyModifiersText(int modifiers) { + return getKeyModifiersExText(extractExFlags(modifiers)); + } + + static String getKeyModifiersExText(int modifiersEx) { + String text = ""; //$NON-NLS-1$ + + if ((modifiersEx & InputEvent.META_DOWN_MASK) != 0) { + text += Toolkit.getProperty("AWT.meta", "Meta"); //$NON-NLS-1$ //$NON-NLS-2$ + } + if ((modifiersEx & InputEvent.CTRL_DOWN_MASK) != 0) { + text += ((text.length() > 0) ? "+" : "") + //$NON-NLS-1$ //$NON-NLS-2$ + Toolkit.getProperty("AWT.control", "Ctrl"); //$NON-NLS-1$ //$NON-NLS-2$ + } + if ((modifiersEx & InputEvent.ALT_DOWN_MASK) != 0) { + text += ((text.length() > 0) ? "+" : "") + //$NON-NLS-1$ //$NON-NLS-2$ + Toolkit.getProperty("AWT.alt", "Alt"); //$NON-NLS-1$ //$NON-NLS-2$ + } + if ((modifiersEx & InputEvent.SHIFT_DOWN_MASK) != 0) { + text += ((text.length() > 0) ? "+" : "") + //$NON-NLS-1$ //$NON-NLS-2$ + Toolkit.getProperty("AWT.shift", "Shift"); //$NON-NLS-1$ //$NON-NLS-2$ + } + if ((modifiersEx & InputEvent.ALT_GRAPH_DOWN_MASK) != 0) { + text += ((text.length() > 0) ? "+" : "") + //$NON-NLS-1$ //$NON-NLS-2$ + Toolkit.getProperty("AWT.altGraph", "Alt Graph"); //$NON-NLS-1$ //$NON-NLS-2$ + } + + return text; + } + + public static String getKeyText(int keyCode) { + String[] rawName = getPublicStaticFinalIntFieldName(keyCode); //$NON-NLS-1$ + + if ((rawName == null) || (rawName.length == 0)) { + return ("Unknown keyCode: " + (keyCode >= 0 ? "0x" : "-0x") + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + Integer.toHexString(Math.abs(keyCode))); + } + + String propertyName = getPropertyName(rawName); + String defaultName = getDefaultName(rawName); + + return Toolkit.getProperty(propertyName, defaultName); + } + + private static String getDefaultName(String[] rawName) { + String name = ""; //$NON-NLS-1$ + + for (int i = 0; true; i++) { + String part = rawName[i]; + + name += new String(new char[] {part.charAt(0)}).toUpperCase() + + part.substring(1).toLowerCase(); + + if (i == (rawName.length - 1)) { + break; + } + name += " "; //$NON-NLS-1$ + } + + return name; + } + + private static String getPropertyName(String[] rawName) { + String name = rawName[0].toLowerCase(); + + for (int i = 1; i < rawName.length; i++) { + String part = rawName[i]; + + name += new String(new char[] {part.charAt(0)}).toUpperCase() + + part.substring(1).toLowerCase(); + } + + return ("AWT." + name); //$NON-NLS-1$ + } + + private static String[] getPublicStaticFinalIntFieldName(int value) { + Field[] allFields = KeyEvent.class.getDeclaredFields(); + + try { + for (Field field : allFields) { + Class ssalc = field.getType(); + int modifiers = field.getModifiers(); + + if (ssalc.isPrimitive() && ssalc.getName().equals("int") && //$NON-NLS-1$ + Modifier.isFinal(modifiers) && Modifier.isPublic(modifiers) && + Modifier.isStatic(modifiers)) + { + if (field.getInt(null) == value){ + final String name = field.getName(); + final int prefixLength = name.indexOf("_") + 1; + return name.substring(prefixLength).split("_"); //$NON-NLS-1$ + } + } + } + } catch (Exception e) { + throw new RuntimeException(e); + } + + return null; + } + + @Deprecated + public KeyEvent(Component src, int id, + long when, int modifiers, + int keyCode) { + this(src, id, when, modifiers, keyCode, + (keyCode > (2 << 7) - 1) ? CHAR_UNDEFINED : (char) keyCode); + } + + public KeyEvent(Component src, int id, + long when, int modifiers, + int keyCode, char keyChar) { + this(src, id, when, modifiers, keyCode, keyChar, KEY_LOCATION_UNKNOWN); + } + + public KeyEvent(Component src, int id, + long when, int modifiers, + int keyCode, char keyChar, + int keyLocation) { + super(src, id, when, modifiers); + + if (id == KEY_TYPED) { + if (keyCode != VK_UNDEFINED) { + // awt.191=Invalid keyCode for KEY_TYPED event, must be VK_UNDEFINED + throw new IllegalArgumentException(Messages.getString("awt.191")); //$NON-NLS-1$ + } + if (keyChar == CHAR_UNDEFINED) { + // awt.192=Invalid keyChar for KEY_TYPED event, can't be CHAR_UNDEFINED + throw new IllegalArgumentException(Messages.getString("awt.192")); //$NON-NLS-1$ + } + } + + if ((keyLocation < KEY_LOCATION_UNKNOWN) + || (keyLocation > KEY_LOCATION_NUMPAD)) { + // awt.297=Invalid keyLocation + throw new IllegalArgumentException(Messages.getString("awt.297")); //$NON-NLS-1$ + } + + this.keyChar = keyChar; + this.keyLocation = keyLocation; + this.keyCode = keyCode; + } + + public int getKeyCode() { + return keyCode; + } + + public void setKeyCode(int keyCode) { + this.keyCode = keyCode; + } + + public char getKeyChar() { + return keyChar; + } + + public void setKeyChar(char keyChar) { + this.keyChar = keyChar; + } + + public int getKeyLocation() { + return keyLocation; + } + + @Override + @Deprecated + public void setModifiers(int modifiers) { + super.setModifiers(modifiers); + } + + public boolean isActionKey() { + return ((keyChar == CHAR_UNDEFINED) && (keyCode != VK_UNDEFINED) && + !((keyCode == VK_ALT) || (keyCode == VK_ALT_GRAPH) || + (keyCode == VK_CONTROL) || (keyCode == VK_META) || (keyCode == VK_SHIFT))); + } + + @Override + public String paramString() { + /* + * The format is based on 1.5 release behavior + * which can be revealed by the following code: + * + * KeyEvent e = new KeyEvent(new Component() {}, + * KeyEvent.KEY_PRESSED, 0, + * KeyEvent.CTRL_DOWN_MASK|KeyEvent.SHIFT_DOWN_MASK, + * KeyEvent.VK_A, 'A', KeyEvent.KEY_LOCATION_STANDARD); + * System.out.println(e); + */ + + String idString = null; + String locString = null; + String paramString = null; + String keyCharString = (keyChar == '\n') ? + keyCharString = getKeyText(VK_ENTER) : "'" + keyChar + "'"; //$NON-NLS-1$ //$NON-NLS-2$ + + switch (id) { + case KEY_PRESSED: + idString = "KEY_PRESSED"; //$NON-NLS-1$ + break; + case KEY_RELEASED: + idString = "KEY_RELEASED"; //$NON-NLS-1$ + break; + case KEY_TYPED: + idString = "KEY_TYPED"; //$NON-NLS-1$ + break; + default: + idString = "unknown type"; //$NON-NLS-1$ + } + + switch(keyLocation){ + case KEY_LOCATION_STANDARD: + locString = "KEY_LOCATION_STANDARD"; //$NON-NLS-1$ + break; + case KEY_LOCATION_LEFT: + locString = "KEY_LOCATION_LEFT"; //$NON-NLS-1$ + break; + case KEY_LOCATION_RIGHT: + locString = "KEY_LOCATION_RIGHT"; //$NON-NLS-1$ + break; + case KEY_LOCATION_NUMPAD: + locString = "KEY_LOCATION_NUMPAD"; //$NON-NLS-1$ + break; + case KEY_LOCATION_UNKNOWN: + locString = "KEY_LOCATION_UNKNOWN"; //$NON-NLS-1$ + break; + default: + locString = "unknown type"; //$NON-NLS-1$ + } + + paramString = idString + ",keyCode=" + keyCode; //$NON-NLS-1$ + if (isActionKey()) { + paramString += "," + getKeyText(keyCode); //$NON-NLS-1$ + } else { + paramString += ",keyChar=" + keyCharString; //$NON-NLS-1$ + } + if (getModifiersEx() > 0) { + paramString += ",modifiers=" + getModifiersExText(getModifiersEx()) + //$NON-NLS-1$ + ",extModifiers=" + getModifiersExText(getModifiersEx()); //$NON-NLS-1$ + } + paramString += ",keyLocation=" + locString; //$NON-NLS-1$ + + return paramString; + } + +} diff --git a/app/src/main/java/java/awt/event/KeyListener.java b/app/src/main/java/java/awt/event/KeyListener.java new file mode 100644 index 000000000..ec144dfef --- /dev/null +++ b/app/src/main/java/java/awt/event/KeyListener.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface KeyListener extends EventListener { + + public void keyPressed(KeyEvent e); + + public void keyReleased(KeyEvent e); + + public void keyTyped(KeyEvent e); + +} diff --git a/app/src/main/java/java/awt/event/MouseAdapter.java b/app/src/main/java/java/awt/event/MouseAdapter.java new file mode 100644 index 000000000..dc19173c3 --- /dev/null +++ b/app/src/main/java/java/awt/event/MouseAdapter.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public abstract class MouseAdapter implements MouseListener { + + public MouseAdapter() { + } + + public void mouseClicked(MouseEvent e) { + } + + public void mouseEntered(MouseEvent e) { + } + + public void mouseExited(MouseEvent e) { + } + + public void mousePressed(MouseEvent e) { + } + + public void mouseReleased(MouseEvent e) { + } + +} diff --git a/app/src/main/java/java/awt/event/MouseEvent.java b/app/src/main/java/java/awt/event/MouseEvent.java new file mode 100644 index 000000000..2b1fa8b2a --- /dev/null +++ b/app/src/main/java/java/awt/event/MouseEvent.java @@ -0,0 +1,232 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.awt.Component; +import java.awt.Point; +import java.awt.Toolkit; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public class MouseEvent extends InputEvent { + + private static final long serialVersionUID = -991214153494842848L; + + public static final int MOUSE_FIRST = 500; + + public static final int MOUSE_LAST = 507; + + public static final int MOUSE_CLICKED = 500; + + public static final int MOUSE_PRESSED = 501; + + public static final int MOUSE_RELEASED = 502; + + public static final int MOUSE_MOVED = 503; + + public static final int MOUSE_ENTERED = 504; + + public static final int MOUSE_EXITED = 505; + + public static final int MOUSE_DRAGGED = 506; + + public static final int MOUSE_WHEEL = 507; + + public static final int NOBUTTON = 0; + + public static final int BUTTON1 = 1; + + public static final int BUTTON2 = 2; + + public static final int BUTTON3 = 3; + + private boolean popupTrigger; + private int clickCount; + private int button; + private int x; + private int y; + + public static String getMouseModifiersText(int modifiers) { + final StringBuffer text = new StringBuffer(); + + if ((modifiers & META_MASK) != 0) { + text.append(Toolkit.getProperty("AWT.meta", "Meta")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + if ((modifiers & SHIFT_MASK) != 0) { + text.append(Toolkit.getProperty("AWT.shift", "Shift")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + if ((modifiers & CTRL_MASK) != 0) { + text.append(Toolkit.getProperty("AWT.control", "Ctrl")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + if ((modifiers & ALT_MASK) != 0) { + text.append(Toolkit.getProperty("AWT.alt", "Alt")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + if ((modifiers & ALT_GRAPH_MASK) != 0) { + text.append(Toolkit.getProperty("AWT.altGraph", "Alt Graph")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + if ((modifiers & BUTTON1_MASK) != 0) { + text.append(Toolkit.getProperty("AWT.button1", "Button1")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + if ((modifiers & BUTTON2_MASK) != 0) { + text.append(Toolkit.getProperty("AWT.button2", "Button2")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + if ((modifiers & BUTTON3_MASK) != 0) { + text.append(Toolkit.getProperty("AWT.button3", "Button3")).append("+"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + return text.length() == 0 ? text.toString() : text.substring(0, text + .length() - 1); + } + + static String addMouseModifiersExText(String text, int modifiersEx) { + if ((modifiersEx & InputEvent.BUTTON1_DOWN_MASK) != 0) { + text += ((text.length() > 0) ? "+" : "") + //$NON-NLS-1$ //$NON-NLS-2$ + Toolkit.getProperty("AWT.button1", "Button1"); //$NON-NLS-1$ //$NON-NLS-2$ + } + if ((modifiersEx & InputEvent.BUTTON2_DOWN_MASK) != 0) { + text += ((text.length() > 0) ? "+" : "") + //$NON-NLS-1$ //$NON-NLS-2$ + Toolkit.getProperty("AWT.button2", "Button2"); //$NON-NLS-1$ //$NON-NLS-2$ + } + if ((modifiersEx & InputEvent.BUTTON3_DOWN_MASK) != 0) { + text += ((text.length() > 0) ? "+" : "") + //$NON-NLS-1$ //$NON-NLS-2$ + Toolkit.getProperty("AWT.button3", "Button3"); //$NON-NLS-1$ //$NON-NLS-2$ + } + + return text; + } + + public MouseEvent(Component source, int id, long when, + int modifiers, int x, int y, + int clickCount, boolean popupTrigger) { + this(source, id, when, modifiers, x, y, + clickCount, popupTrigger, NOBUTTON); + } + + public MouseEvent(Component source, int id, long when, + int modifiers, int x, int y, + int clickCount, boolean popupTrigger, int button) { + super(source, id, when, modifiers); + + if ((button != NOBUTTON) && (button != BUTTON1) && + (button != BUTTON2) && (button != BUTTON3)) { + // awt.18B=Invalid button value + throw new IllegalArgumentException(Messages.getString("awt.18B")); //$NON-NLS-1$ + } + + this.popupTrigger = popupTrigger; + this.clickCount = clickCount; + this.button = button; + this.x = x; + this.y = y; + } + + public int getButton() { + return button; + } + + public int getClickCount() { + return clickCount; + } + + public Point getPoint() { + return new Point(x, y); + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + + public boolean isPopupTrigger() { + return popupTrigger; + } + + public void translatePoint(int x, int y) { + this.x += x; + this.y += y; + } + + @Override + public String paramString() { + /* The format is based on 1.5 release behavior + * which can be revealed by the following code: + * + * MouseEvent e = new MouseEvent(new Component(){}, + * MouseEvent.MOUSE_PRESSED, 0, + * MouseEvent.BUTTON1_DOWN_MASK|MouseEvent.CTRL_DOWN_MASK, + * 10, 20, 1, false, MouseEvent.BUTTON1); + * System.out.println(e); + */ + + String idString = null; + String paramString = null; + + switch (id) { + case MOUSE_MOVED: + idString = "MOUSE_MOVED"; //$NON-NLS-1$ + break; + case MOUSE_CLICKED: + idString = "MOUSE_CLICKED"; //$NON-NLS-1$ + break; + case MOUSE_PRESSED: + idString = "MOUSE_PRESSED"; //$NON-NLS-1$ + break; + case MOUSE_RELEASED: + idString = "MOUSE_RELEASED"; //$NON-NLS-1$ + break; + case MOUSE_DRAGGED: + idString = "MOUSE_DRAGGED"; //$NON-NLS-1$ + break; + case MOUSE_ENTERED: + idString = "MOUSE_ENTERED"; //$NON-NLS-1$ + break; + case MOUSE_EXITED: + idString = "MOUSE_EXITED"; //$NON-NLS-1$ + break; + case MOUSE_WHEEL: + idString = "MOUSE_WHEEL"; //$NON-NLS-1$ + break; + default: + idString = "unknown type"; //$NON-NLS-1$ + } + + paramString = idString + ",(" + getX() + "," + getY() + ")" + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + ",button=" + button; //$NON-NLS-1$ + if (getModifiersEx() > 0) { + paramString += + ",modifiers=" + getModifiersExText(getModifiersEx()) + //$NON-NLS-1$ + ",extModifiers=" + getModifiersExText(getModifiersEx()); //$NON-NLS-1$ + } + paramString += ",clickCount=" + getClickCount(); //$NON-NLS-1$ + + return paramString; + } + +} diff --git a/app/src/main/java/java/awt/event/MouseListener.java b/app/src/main/java/java/awt/event/MouseListener.java new file mode 100644 index 000000000..95879b90e --- /dev/null +++ b/app/src/main/java/java/awt/event/MouseListener.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface MouseListener extends EventListener { + + public void mouseClicked(MouseEvent e); + + public void mouseEntered(MouseEvent e); + + public void mouseExited(MouseEvent e); + + public void mousePressed(MouseEvent e); + + public void mouseReleased(MouseEvent e); + +} diff --git a/app/src/main/java/java/awt/event/MouseMotionAdapter.java b/app/src/main/java/java/awt/event/MouseMotionAdapter.java new file mode 100644 index 000000000..1ecd0d5ad --- /dev/null +++ b/app/src/main/java/java/awt/event/MouseMotionAdapter.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public abstract class MouseMotionAdapter implements MouseMotionListener { + + public MouseMotionAdapter() { + } + + public void mouseDragged(MouseEvent e) { + } + + public void mouseMoved(MouseEvent e) { + } + +} diff --git a/app/src/main/java/java/awt/event/MouseMotionListener.java b/app/src/main/java/java/awt/event/MouseMotionListener.java new file mode 100644 index 000000000..e1313c340 --- /dev/null +++ b/app/src/main/java/java/awt/event/MouseMotionListener.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface MouseMotionListener extends EventListener { + + public void mouseDragged(MouseEvent e); + + public void mouseMoved(MouseEvent e); + +} diff --git a/app/src/main/java/java/awt/event/MouseWheelEvent.java b/app/src/main/java/java/awt/event/MouseWheelEvent.java new file mode 100644 index 000000000..a3ed42436 --- /dev/null +++ b/app/src/main/java/java/awt/event/MouseWheelEvent.java @@ -0,0 +1,103 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.awt.Component; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public class MouseWheelEvent extends MouseEvent { + + private static final long serialVersionUID = -9187413581993563929L; + + public static final int WHEEL_UNIT_SCROLL = 0; + + public static final int WHEEL_BLOCK_SCROLL = 1; + + private int wheelRotation; + private int scrollAmount; + private int scrollType; + + public MouseWheelEvent(Component source, int id, long when, int modifiers, + int x, int y, int clickCount, boolean popupTrigger, int scrollType, + int scrollAmount, int wheelRotation) { + super(source, id, when, modifiers, x, y, clickCount, popupTrigger); + + this.scrollType = scrollType; + this.scrollAmount = scrollAmount; + this.wheelRotation = wheelRotation; + } + + public int getScrollAmount() { + return scrollAmount; + } + + public int getScrollType() { + return scrollType; + } + + public int getWheelRotation() { + return wheelRotation; + } + + public int getUnitsToScroll() { + return (scrollAmount * wheelRotation); + } + + @Override + public String paramString() { + /* The format is based on 1.5 release behavior + * which can be revealed by the following code: + * + * MouseWheelEvent e = new MouseWheelEvent(new Component(){}, + * MouseWheelEvent.MOUSE_WHEEL, 0, + * MouseEvent.BUTTON1_DOWN_MASK|MouseEvent.CTRL_DOWN_MASK, + * 10, 20, 1, false, MouseWheelEvent.WHEEL_UNIT_SCROLL, + * 1, 3); + * System.out.println(e); + */ + + String paramString = super.paramString(); + String typeString = null; + + switch (scrollType) { + case WHEEL_UNIT_SCROLL: + typeString = "WHEEL_UNIT_SCROLL"; //$NON-NLS-1$ + break; + case WHEEL_BLOCK_SCROLL: + typeString = "WHEEL_BLOCK_SCROLL"; //$NON-NLS-1$ + break; + default: + typeString = "unknown type"; //$NON-NLS-1$ + } + + paramString += ",scrollType=" + typeString + //$NON-NLS-1$ + ",scrollAmount=" + scrollAmount + //$NON-NLS-1$ + ",wheelRotation=" + wheelRotation; //$NON-NLS-1$ + + return paramString; + } + +} diff --git a/app/src/main/java/java/awt/event/MouseWheelListener.java b/app/src/main/java/java/awt/event/MouseWheelListener.java new file mode 100644 index 000000000..2d6a98236 --- /dev/null +++ b/app/src/main/java/java/awt/event/MouseWheelListener.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface MouseWheelListener extends EventListener { + + public void mouseWheelMoved(MouseWheelEvent e); + +} diff --git a/app/src/main/java/java/awt/event/PaintEvent.java b/app/src/main/java/java/awt/event/PaintEvent.java new file mode 100644 index 000000000..22ac0908d --- /dev/null +++ b/app/src/main/java/java/awt/event/PaintEvent.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.awt.Component; +import java.awt.Rectangle; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public class PaintEvent extends ComponentEvent { + + private static final long serialVersionUID = 1267492026433337593L; + + public static final int PAINT_FIRST = 800; + + public static final int PAINT_LAST = 801; + + public static final int PAINT = 800; + + public static final int UPDATE = 801; + + private Rectangle updateRect; + + public PaintEvent(Component source, int id, Rectangle updateRect) { + super(source, id); + + this.updateRect = updateRect; + } + + public Rectangle getUpdateRect() { + return updateRect; + } + + public void setUpdateRect(Rectangle updateRect) { + this.updateRect = updateRect; + } + + @Override + public String paramString() { + /* The format is based on 1.5 release behavior + * which can be revealed by the following code: + * + * PaintEvent e = new PaintEvent(new Component(){}, + * PaintEvent.PAINT, new Rectangle(0, 0, 10, 20)); + * System.out.println(e); + */ + + String typeString = null; + + switch (id) { + case PAINT: + typeString = "PAINT"; //$NON-NLS-1$ + break; + case UPDATE: + typeString = "UPDATE"; //$NON-NLS-1$ + break; + default: + typeString = "unknown type"; //$NON-NLS-1$ + } + + return typeString + ",updateRect=" + updateRect; //$NON-NLS-1$ + } + +} diff --git a/app/src/main/java/java/awt/event/TextEvent.java b/app/src/main/java/java/awt/event/TextEvent.java new file mode 100644 index 000000000..2a690ad50 --- /dev/null +++ b/app/src/main/java/java/awt/event/TextEvent.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.awt.AWTEvent; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public class TextEvent extends AWTEvent { + + private static final long serialVersionUID = 6269902291250941179L; + + public static final int TEXT_FIRST = 900; + + public static final int TEXT_LAST = 900; + + public static final int TEXT_VALUE_CHANGED = 900; + + public TextEvent(Object src, int id) { + super(src, id); + } + + @Override + public String paramString() { + /* The format is based on 1.5 release behavior + * which can be revealed by the following code: + * + * TextEvent e = new TextEvent(new Component(){}, + * TextEvent.TEXT_VALUE_CHANGED); + * System.out.println(e); + */ + + return (id == TEXT_VALUE_CHANGED) ? + "TEXT_VALUE_CHANGED" : "unknown type"; //$NON-NLS-1$ //$NON-NLS-2$ + } + +} diff --git a/app/src/main/java/java/awt/event/TextListener.java b/app/src/main/java/java/awt/event/TextListener.java new file mode 100644 index 000000000..05757c42a --- /dev/null +++ b/app/src/main/java/java/awt/event/TextListener.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface TextListener extends EventListener { + + public void textValueChanged(TextEvent e); + +} + diff --git a/app/src/main/java/java/awt/event/WindowAdapter.java b/app/src/main/java/java/awt/event/WindowAdapter.java index ae2cead8d..970aa8de4 100644 --- a/app/src/main/java/java/awt/event/WindowAdapter.java +++ b/app/src/main/java/java/awt/event/WindowAdapter.java @@ -1,5 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ package java.awt.event; -public class WindowAdapter implements WindowListener -{ +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public abstract class WindowAdapter implements WindowListener, WindowStateListener, WindowFocusListener { + + public WindowAdapter() { + } + + public void windowActivated(WindowEvent e) { + } + + public void windowClosed(WindowEvent e) { + } + + public void windowClosing(WindowEvent e) { + } + + public void windowDeactivated(WindowEvent e) { + } + + public void windowDeiconified(WindowEvent e) { + } + + public void windowGainedFocus(WindowEvent e) { + } + + public void windowIconified(WindowEvent e) { + } + + public void windowLostFocus(WindowEvent e) { + } + + public void windowOpened(WindowEvent e) { + } + + public void windowStateChanged(WindowEvent e) { + } + } diff --git a/app/src/main/java/java/awt/event/WindowEvent.java b/app/src/main/java/java/awt/event/WindowEvent.java index d0330ff82..474d2ac82 100644 --- a/app/src/main/java/java/awt/event/WindowEvent.java +++ b/app/src/main/java/java/awt/event/WindowEvent.java @@ -1,431 +1,168 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. + * http://www.apache.org/licenses/LICENSE-2.0 * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ */ - package java.awt.event; -import java.awt.Window; -import java.lang.annotation.Native; + +//???AWT +//import java.awt.Window; +//import java.awt.Frame; /** - * A low-level event that indicates that a window has changed its status. This - * low-level event is generated by a Window object when it is opened, closed, - * activated, deactivated, iconified, or deiconified, or when focus is - * transfered into or out of the Window. - *

- * The event is passed to every WindowListener - * or WindowAdapter object which registered to receive such - * events using the window's addWindowListener method. - * (WindowAdapter objects implement the - * WindowListener interface.) Each such listener object - * gets this WindowEvent when the event occurs. - *

- * An unspecified behavior will be caused if the {@code id} parameter - * of any particular {@code WindowEvent} instance is not - * in the range from {@code WINDOW_FIRST} to {@code WINDOW_LAST}. - * - * @author Carl Quinn - * @author Amy Fowler - * - * @see WindowAdapter - * @see WindowListener - * @see Tutorial: Writing a Window Listener - * - * @since JDK1.1 + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 */ -public class WindowEvent /* extends ComponentEvent */ { +public class WindowEvent extends ComponentEvent { - /** - * The first number in the range of ids used for window events. - */ - public static final int WINDOW_FIRST = 200; - - /** - * The window opened event. This event is delivered only - * the first time a window is made visible. - */ - @Native public static final int WINDOW_OPENED = WINDOW_FIRST; // 200 - - /** - * The "window is closing" event. This event is delivered when - * the user attempts to close the window from the window's system menu. - * If the program does not explicitly hide or dispose the window - * while processing this event, the window close operation will be - * cancelled. - */ - @Native public static final int WINDOW_CLOSING = 1 + WINDOW_FIRST; //Event.WINDOW_DESTROY - - /** - * The window closed event. This event is delivered after the displayable - * window has been closed as the result of a call to dispose. - * @see java.awt.Component#isDisplayable - * @see Window#dispose - */ - @Native public static final int WINDOW_CLOSED = 2 + WINDOW_FIRST; - - /** - * The window iconified event. This event is delivered when - * the window has been changed from a normal to a minimized state. - * For many platforms, a minimized window is displayed as - * the icon specified in the window's iconImage property. - * @see java.awt.Frame#setIconImage - */ - @Native public static final int WINDOW_ICONIFIED = 3 + WINDOW_FIRST; //Event.WINDOW_ICONIFY - - /** - * The window deiconified event type. This event is delivered when - * the window has been changed from a minimized to a normal state. - */ - @Native public static final int WINDOW_DEICONIFIED = 4 + WINDOW_FIRST; //Event.WINDOW_DEICONIFY - - /** - * The window-activated event type. This event is delivered when the Window - * becomes the active Window. Only a Frame or a Dialog can be the active - * Window. The native windowing system may denote the active Window or its - * children with special decorations, such as a highlighted title bar. The - * active Window is always either the focused Window, or the first Frame or - * Dialog that is an owner of the focused Window. - */ - @Native public static final int WINDOW_ACTIVATED = 5 + WINDOW_FIRST; - - /** - * The window-deactivated event type. This event is delivered when the - * Window is no longer the active Window. Only a Frame or a Dialog can be - * the active Window. The native windowing system may denote the active - * Window or its children with special decorations, such as a highlighted - * title bar. The active Window is always either the focused Window, or the - * first Frame or Dialog that is an owner of the focused Window. - */ - @Native public static final int WINDOW_DEACTIVATED = 6 + WINDOW_FIRST; - - /** - * The window-gained-focus event type. This event is delivered when the - * Window becomes the focused Window, which means that the Window, or one - * of its subcomponents, will receive keyboard events. - */ - @Native public static final int WINDOW_GAINED_FOCUS = 7 + WINDOW_FIRST; - - /** - * The window-lost-focus event type. This event is delivered when a Window - * is no longer the focused Window, which means keyboard events will no - * longer be delivered to the Window or any of its subcomponents. - */ - @Native public static final int WINDOW_LOST_FOCUS = 8 + WINDOW_FIRST; - - /** - * The window-state-changed event type. This event is delivered - * when a Window's state is changed by virtue of it being - * iconified, maximized etc. - * @since 1.4 - */ - @Native public static final int WINDOW_STATE_CHANGED = 9 + WINDOW_FIRST; - - /** - * The last number in the range of ids used for window events. - */ - public static final int WINDOW_LAST = WINDOW_STATE_CHANGED; - - /** - * The other Window involved in this focus or activation change. For a - * WINDOW_ACTIVATED or WINDOW_GAINED_FOCUS event, this is the Window that - * lost activation or focus. For a WINDOW_DEACTIVATED or WINDOW_LOST_FOCUS - * event, this is the Window that gained activation or focus. For any other - * type of WindowEvent, or if the focus or activation change occurs with a - * native application, a Java application in a different VM, or with no - * other Window, null is returned. - * - * @see #getOppositeWindow - * @since 1.4 - */ - transient Window opposite; - - /** - * TBS - */ - int oldState; - int newState; - - - /* - * JDK 1.1 serialVersionUID - */ private static final long serialVersionUID = -1567959133147912127L; + public static final int WINDOW_FIRST = 200; - /** - * Constructs a WindowEvent object. - *

This method throws an - * IllegalArgumentException if source - * is null. - * - * @param source The Window object - * that originated the event - * @param id An integer indicating the type of event. - * For information on allowable values, see - * the class description for {@link WindowEvent} - * @param opposite The other window involved in the focus or activation - * change, or null - * @param oldState Previous state of the window for window state change event. - * See {@code #getOldState()} for allowable values - * @param newState New state of the window for window state change event. - * See {@code #getNewState()} for allowable values - * @throws IllegalArgumentException if source is null - * @see #getWindow() - * @see #getID() - * @see #getOppositeWindow() - * @see #getOldState() - * @see #getNewState() - * @since 1.4 - */ - public WindowEvent(Window source, int id, Window opposite, - int oldState, int newState) - { - // super(source, id); - this.opposite = opposite; - this.oldState = oldState; - this.newState = newState; + public static final int WINDOW_OPENED = 200; + + public static final int WINDOW_CLOSING = 201; + + public static final int WINDOW_CLOSED = 202; + + public static final int WINDOW_ICONIFIED = 203; + + public static final int WINDOW_DEICONIFIED = 204; + + public static final int WINDOW_ACTIVATED = 205; + + public static final int WINDOW_DEACTIVATED = 206; + + public static final int WINDOW_GAINED_FOCUS = 207; + + public static final int WINDOW_LOST_FOCUS = 208; + + public static final int WINDOW_STATE_CHANGED = 209; + + public static final int WINDOW_LAST = 209; + + //???AWT: private Window oppositeWindow; + private int oldState; + private int newState; + + //???AWT + /* + public WindowEvent(Window source, int id) { + this(source, id, null); } - /** - * Constructs a WindowEvent object with the - * specified opposite Window. The opposite - * Window is the other Window - * involved in this focus or activation change. - * For a WINDOW_ACTIVATED or - * WINDOW_GAINED_FOCUS event, this is the - * Window that lost activation or focus. - * For a WINDOW_DEACTIVATED or - * WINDOW_LOST_FOCUS event, this is the - * Window that gained activation or focus. - * If this focus change occurs with a native application, with a - * Java application in a different VM, or with no other - * Window, then the opposite Window is null. - *

This method throws an - * IllegalArgumentException if source - * is null. - * - * @param source The Window object that - * originated the event - * @param id An integer indicating the type of event. - * For information on allowable values, see - * the class description for {@link WindowEvent}. - * It is expected that this constructor will not - * be used for other then - * {@code WINDOW_ACTIVATED},{@code WINDOW_DEACTIVATED}, - * {@code WINDOW_GAINED_FOCUS}, or {@code WINDOW_LOST_FOCUS}. - * {@code WindowEvent} types, - * because the opposite Window of other event types - * will always be {@code null}. - * @param opposite The other Window involved in the - * focus or activation change, or null - * @throws IllegalArgumentException if source is null - * @see #getWindow() - * @see #getID() - * @see #getOppositeWindow() - * @since 1.4 - */ public WindowEvent(Window source, int id, Window opposite) { - this(source, id, opposite, 0, 0); + this(source, id, opposite, Frame.NORMAL, Frame.NORMAL); } - /** - * Constructs a WindowEvent object with the specified - * previous and new window states. - *

This method throws an - * IllegalArgumentException if source - * is null. - * - * @param source The Window object - * that originated the event - * @param id An integer indicating the type of event. - * For information on allowable values, see - * the class description for {@link WindowEvent}. - * It is expected that this constructor will not - * be used for other then - * {@code WINDOW_STATE_CHANGED} - * {@code WindowEvent} - * types, because the previous and new window - * states are meaningless for other event types. - * @param oldState An integer representing the previous window state. - * See {@code #getOldState()} for allowable values - * @param newState An integer representing the new window state. - * See {@code #getNewState()} for allowable values - * @throws IllegalArgumentException if source is null - * @see #getWindow() - * @see #getID() - * @see #getOldState() - * @see #getNewState() - * @since 1.4 - */ public WindowEvent(Window source, int id, int oldState, int newState) { this(source, id, null, oldState, newState); } - /** - * Constructs a WindowEvent object. - *

This method throws an - * IllegalArgumentException if source - * is null. - * - * @param source The Window object that originated the event - * @param id An integer indicating the type of event. - * For information on allowable values, see - * the class description for {@link WindowEvent}. - * @throws IllegalArgumentException if source is null - * @see #getWindow() - * @see #getID() - */ - public WindowEvent(Window source, int id) { - this(source, id, null, 0, 0); + public WindowEvent(Window source, int id, Window opposite, + int oldState, int newState) { + super(source, id); + + oppositeWindow = opposite; + this.oldState = oldState; + this.newState = newState; } - - /** - * Returns the originator of the event. - * - * @return the Window object that originated the event - */ - public Window getWindow() { - return null; // (source instanceof Window) ? (Window)source : null; + */ + //???AWT: Fake constructor + public WindowEvent() { + super(null, 0); } - - /** - * Returns the other Window involved in this focus or activation change. - * For a WINDOW_ACTIVATED or WINDOW_GAINED_FOCUS event, this is the Window - * that lost activation or focus. For a WINDOW_DEACTIVATED or - * WINDOW_LOST_FOCUS event, this is the Window that gained activation or - * focus. For any other type of WindowEvent, or if the focus or activation - * change occurs with a native application, with a Java application in a - * different VM or context, or with no other Window, null is returned. - * - * @return the other Window involved in the focus or activation change, or - * null - * @since 1.4 - */ - public Window getOppositeWindow() { - if (opposite == null) { - return null; - } - /* - return (SunToolkit.targetToAppContext(opposite) == - AppContext.getAppContext()) - ? opposite - : null; - */ - return opposite; - } - - /** - * For WINDOW_STATE_CHANGED events returns the - * previous state of the window. The state is - * represented as a bitwise mask. - *

    - *
  • NORMAL - *
    Indicates that no state bits are set. - *
  • ICONIFIED - *
  • MAXIMIZED_HORIZ - *
  • MAXIMIZED_VERT - *
  • MAXIMIZED_BOTH - *
    Concatenates MAXIMIZED_HORIZ - * and MAXIMIZED_VERT. - *
- * - * @return a bitwise mask of the previous window state - * @see java.awt.Frame#getExtendedState() - * @since 1.4 - */ - public int getOldState() { - return oldState; - } - - /** - * For WINDOW_STATE_CHANGED events returns the - * new state of the window. The state is - * represented as a bitwise mask. - *
    - *
  • NORMAL - *
    Indicates that no state bits are set. - *
  • ICONIFIED - *
  • MAXIMIZED_HORIZ - *
  • MAXIMIZED_VERT - *
  • MAXIMIZED_BOTH - *
    Concatenates MAXIMIZED_HORIZ - * and MAXIMIZED_VERT. - *
- * - * @return a bitwise mask of the new window state - * @see java.awt.Frame#getExtendedState() - * @since 1.4 - */ + public int getNewState() { return newState; } - /** - * Returns a parameter string identifying this event. - * This method is useful for event-logging and for debugging. - * - * @return a string identifying the event and its attributes - */ - public String paramString() { - String typeStr; - switch(0) { // id - case WINDOW_OPENED: - typeStr = "WINDOW_OPENED"; - break; - case WINDOW_CLOSING: - typeStr = "WINDOW_CLOSING"; - break; - case WINDOW_CLOSED: - typeStr = "WINDOW_CLOSED"; - break; - case WINDOW_ICONIFIED: - typeStr = "WINDOW_ICONIFIED"; - break; - case WINDOW_DEICONIFIED: - typeStr = "WINDOW_DEICONIFIED"; - break; - case WINDOW_ACTIVATED: - typeStr = "WINDOW_ACTIVATED"; - break; - case WINDOW_DEACTIVATED: - typeStr = "WINDOW_DEACTIVATED"; - break; - case WINDOW_GAINED_FOCUS: - typeStr = "WINDOW_GAINED_FOCUS"; - break; - case WINDOW_LOST_FOCUS: - typeStr = "WINDOW_LOST_FOCUS"; - break; - case WINDOW_STATE_CHANGED: - typeStr = "WINDOW_STATE_CHANGED"; - break; - default: - typeStr = "unknown type"; - } - typeStr += ",opposite=" + getOppositeWindow() - + ",oldState=" + oldState + ",newState=" + newState; - - return typeStr; + public int getOldState() { + return oldState; } + + //???AWT + /* + public Window getOppositeWindow() { + return oppositeWindow; + } + + public Window getWindow() { + return (Window) source; + } + */ + + @Override + public String paramString() { + /* The format is based on 1.5 release behavior + * which can be revealed by the following code: + * + * WindowEvent e = new WindowEvent(new Frame(), + * WindowEvent.WINDOW_OPENED); + * System.out.println(e); + */ + + String typeString = null; + + switch (id) { + case WINDOW_OPENED: + typeString = "WINDOW_OPENED"; //$NON-NLS-1$ + break; + case WINDOW_CLOSING: + typeString = "WINDOW_CLOSING"; //$NON-NLS-1$ + break; + case WINDOW_CLOSED: + typeString = "WINDOW_CLOSED"; //$NON-NLS-1$ + break; + case WINDOW_ICONIFIED: + typeString = "WINDOW_ICONIFIED"; //$NON-NLS-1$ + break; + case WINDOW_DEICONIFIED: + typeString = "WINDOW_DEICONIFIED"; //$NON-NLS-1$ + break; + case WINDOW_ACTIVATED: + typeString = "WINDOW_ACTIVATED"; //$NON-NLS-1$ + break; + case WINDOW_DEACTIVATED: + typeString = "WINDOW_DEACTIVATED"; //$NON-NLS-1$ + break; + case WINDOW_GAINED_FOCUS: + typeString = "WINDOW_GAINED_FOCUS"; //$NON-NLS-1$ + break; + case WINDOW_LOST_FOCUS: + typeString = "WINDOW_LOST_FOCUS"; //$NON-NLS-1$ + break; + case WINDOW_STATE_CHANGED: + typeString = "WINDOW_STATE_CHANGED"; //$NON-NLS-1$ + break; + default: + typeString = "unknown type"; //$NON-NLS-1$ + } + + //???AWT + /* + return typeString + ",opposite=" + oppositeWindow + //$NON-NLS-1$ + ",oldState=" + oldState + ",newState=" + newState; //$NON-NLS-1$ //$NON-NLS-2$ + */ + return typeString; + } + } diff --git a/app/src/main/java/java/awt/event/WindowFocusListener.java b/app/src/main/java/java/awt/event/WindowFocusListener.java new file mode 100644 index 000000000..528459f3b --- /dev/null +++ b/app/src/main/java/java/awt/event/WindowFocusListener.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface WindowFocusListener extends EventListener { + + public void windowGainedFocus(WindowEvent e); + + public void windowLostFocus(WindowEvent e); + +} diff --git a/app/src/main/java/java/awt/event/WindowListener.java b/app/src/main/java/java/awt/event/WindowListener.java index d326597de..31bd547bd 100644 --- a/app/src/main/java/java/awt/event/WindowListener.java +++ b/app/src/main/java/java/awt/event/WindowListener.java @@ -1,5 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ package java.awt.event; -public interface WindowListener -{ +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface WindowListener extends EventListener { + + public void windowActivated(WindowEvent e); + + public void windowClosed(WindowEvent e); + + public void windowClosing(WindowEvent e); + + public void windowDeactivated(WindowEvent e); + + public void windowDeiconified(WindowEvent e); + + public void windowIconified(WindowEvent e); + + public void windowOpened(WindowEvent e); + } diff --git a/app/src/main/java/java/awt/event/WindowStateListener.java b/app/src/main/java/java/awt/event/WindowStateListener.java new file mode 100644 index 000000000..ba14d9ee8 --- /dev/null +++ b/app/src/main/java/java/awt/event/WindowStateListener.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov + * @version $Revision$ + */ +package java.awt.event; + +import java.util.EventListener; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface WindowStateListener extends EventListener { + + public void windowStateChanged(WindowEvent e); + +} + diff --git a/app/src/main/java/java/awt/font/FontRenderContext.java b/app/src/main/java/java/awt/font/FontRenderContext.java new file mode 100644 index 000000000..d7de00f20 --- /dev/null +++ b/app/src/main/java/java/awt/font/FontRenderContext.java @@ -0,0 +1,178 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ +package java.awt.font; + +import java.awt.geom.AffineTransform; + +/** + * The FontRenderContext class contains the information about text measurement. + * Anti-aliasing and fractional-metrics modes are defined by an application and + * affect the size of a character. + * + * @since Android 1.0 + */ +public class FontRenderContext { + + // Affine transform of this mode + /** + * The transform. + */ + private AffineTransform transform; + + // Is the anti-aliased mode used + /** + * The anti aliased. + */ + private boolean fAntiAliased; + + // Is the fractional metrics used + /** + * The fractional metrics. + */ + private boolean fFractionalMetrics; + + + /** + * Instantiates a new FontRenderContext object with the specified + * AffineTransform, anti-aliasing and fractional metrics flags. + * + * @param trans + * the AffineTransform. + * @param antiAliased + * the anti-aliasing flag. + * @param usesFractionalMetrics + * the fractional metrics flag. + */ + public FontRenderContext(AffineTransform trans, boolean antiAliased, + boolean usesFractionalMetrics) { + if (trans != null){ + transform = new AffineTransform(trans); + } + fAntiAliased = antiAliased; + fFractionalMetrics = usesFractionalMetrics; + } + + /** + * Instantiates a new FontRenderContext object. + */ + protected FontRenderContext() { + } + + /** + * Compares the specified Object with current FontRenderContext object. + * + * @param obj + * the Object to be compared. + * @return true, if the specified Object is equal to current + * FontRenderContext object. + */ + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + + if (obj != null) { + try { + return equals((FontRenderContext) obj); + } catch (ClassCastException e) { + return false; + } + } + return false; + + } + + /** + * Gets the transform which is used for scaling typographical points to + * pixels in this FontRenderContext. + * + * @return the AffineTransform which is used for scaling typographical + * points to pixels in this FontRenderContext. + */ + public AffineTransform getTransform() { + if (transform != null){ + return new AffineTransform(transform); + } + return new AffineTransform(); + } + + /** + * Compares the specified FontRenderContext object with current + * FontRenderContext. + * + * @param frc + * the FontRenderContext object to be compared. + * @return true, if the specified FontRenderContext object is equal to + * current FontRenderContext. + */ + public boolean equals(FontRenderContext frc) { + if (this == frc){ + return true; + } + + if (frc == null){ + return false; + } + + if (!frc.getTransform().equals(this.getTransform()) && + !frc.isAntiAliased() == this.fAntiAliased && + !frc.usesFractionalMetrics() == this.fFractionalMetrics){ + return false; + } + return true; + } + + /** + * Returns true if the text fractional metrics are used in this + * FontRenderContext. + * + * @return true, if the text fractional metrics are used in this + * FontRenderContext, false otherwise. + */ + public boolean usesFractionalMetrics() { + return this.fFractionalMetrics; + } + + /** + * Returns true if anti-aliasing is used in this FontRenderContext. + * + * @return true, if is anti-aliasing is used in this FontRenderContext, + * false otherwise. + */ + public boolean isAntiAliased() { + return this.fAntiAliased; + } + + /** + * Returns hash code of the FontRenderContext object. + * + * @return the hash code of the FontRenderContext object. + */ + @Override + public int hashCode() { + return this.getTransform().hashCode() ^ + new Boolean(this.fFractionalMetrics).hashCode() ^ + new Boolean(this.fAntiAliased).hashCode(); + } + +} + diff --git a/app/src/main/java/java/awt/font/GlyphJustificationInfo.java b/app/src/main/java/java/awt/font/GlyphJustificationInfo.java new file mode 100644 index 000000000..b03de0aa1 --- /dev/null +++ b/app/src/main/java/java/awt/font/GlyphJustificationInfo.java @@ -0,0 +1,197 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ + +package java.awt.font; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The GlyphJustificationInfo class provides information about the glyph's + * justification properties. There are four justification properties: weight, + * priority, absorb, and limit. + *

+ * There are two sets of metrics: growing and shrinking. Growing metrics are + * used when the glyphs are to be spread apart to fit a larger width. Shrinking + * metrics are used when the glyphs are to be moved together to fit a smaller + * width. + *

+ * + * @since Android 1.0 + */ +public final class GlyphJustificationInfo { + + /** + * The Constant PRIORITY_KASHIDA indicates the highest justification + * priority. + */ + public static final int PRIORITY_KASHIDA = 0; + + /** + * The Constant PRIORITY_WHITESPACE indicates the second highest + * justification priority. + */ + public static final int PRIORITY_WHITESPACE = 1; + + /** + * The Constant PRIORITY_INTERCHAR indicates the second lowest justification + * priority. + */ + public static final int PRIORITY_INTERCHAR = 2; + + /** + * The Constant PRIORITY_NONE indicates the lowest justification priority. + */ + public static final int PRIORITY_NONE = 3; + + /** + * The grow absorb flag indicates if this glyph absorbs all extra space at + * this and lower priority levels when it grows. + */ + public final boolean growAbsorb; + + /** + * The grow left limit value represents the maximum value by which the left + * side of this glyph grows. + */ + public final float growLeftLimit; + + /** + * The grow right limit value repesents the maximum value by which the right + * side of this glyph grows. + */ + public final float growRightLimit; + + /** + * The grow priority value represents the priority level of this glyph as it + * is growing. + */ + public final int growPriority; + + /** + * The shrink absorb fleg indicates this glyph absorbs all remaining + * shrinkage at this and lower priority levels as it shrinks. + */ + public final boolean shrinkAbsorb; + + /** + * The shrink left limit value represents the maximum value by which the + * left side of this glyph shrinks. + */ + public final float shrinkLeftLimit; + + /** + * The shrink right limit value represents the maximum value by which the + * right side of this glyph shrinks. + */ + public final float shrinkRightLimit; + + /** + * The shrink priority represents the glyth's priority level as it is + * shrinking. + */ + public final int shrinkPriority; + + /** + * The weight of the glyph. + */ + public final float weight; + + /** + * Instantiates a new GlyphJustificationInfo object which contains glyph's + * justification properties. + * + * @param weight + * the weight of glyph. + * @param growAbsorb + * indicates if this glyph contais all space at this priority and + * lower priority levels when it grows. + * @param growPriority + * indicates the priority level of this glyph when it grows. + * @param growLeftLimit + * indicates the maximum value of which the left side of this + * glyph can grow. + * @param growRightLimit + * the maximum value of which the right side of this glyph can + * grow. + * @param shrinkAbsorb + * indicates if this glyph contains all remaining shrinkage at + * this and lower priority levels when it shrinks. + * @param shrinkPriority + * indicates the glyph's priority level when it shrinks. + * @param shrinkLeftLimit + * indicates the maximum value of which the left side of this + * glyph can shrink. + * @param shrinkRightLimit + * indicates the maximum amount by which the right side of this + * glyph can shrink. + */ + public GlyphJustificationInfo(float weight, boolean growAbsorb, int growPriority, + float growLeftLimit, float growRightLimit, boolean shrinkAbsorb, int shrinkPriority, + float shrinkLeftLimit, float shrinkRightLimit) { + + if (weight < 0) { + // awt.19C=weight must be a positive number + throw new IllegalArgumentException(Messages.getString("awt.19C")); //$NON-NLS-1$ + } + this.weight = weight; + + if (growLeftLimit < 0) { + // awt.19D=growLeftLimit must be a positive number + throw new IllegalArgumentException(Messages.getString("awt.19D")); //$NON-NLS-1$ + } + this.growLeftLimit = growLeftLimit; + + if (growRightLimit < 0) { + // awt.19E=growRightLimit must be a positive number + throw new IllegalArgumentException(Messages.getString("awt.19E")); //$NON-NLS-1$ + } + this.growRightLimit = growRightLimit; + + if ((shrinkPriority < 0) || (shrinkPriority > PRIORITY_NONE)) { + // awt.19F=incorrect value for shrinkPriority, more than + // PRIORITY_NONE or less than PRIORITY_KASHIDA value + throw new IllegalArgumentException(Messages.getString("awt.19F")); //$NON-NLS-1$ + } + this.shrinkPriority = shrinkPriority; + + if ((growPriority < 0) || (growPriority > PRIORITY_NONE)) { + // awt.200=incorrect value for growPriority, more than PRIORITY_NONE + // or less than PRIORITY_KASHIDA value + throw new IllegalArgumentException(Messages.getString("awt.200")); //$NON-NLS-1$ + } + this.growPriority = growPriority; + + if (shrinkLeftLimit < 0) { + // awt.201=shrinkLeftLimit must be a positive number + throw new IllegalArgumentException(Messages.getString("awt.201")); //$NON-NLS-1$ + } + this.shrinkLeftLimit = shrinkLeftLimit; + + if (shrinkRightLimit < 0) { + // awt.202=shrinkRightLimit must be a positive number + throw new IllegalArgumentException(Messages.getString("awt.202")); //$NON-NLS-1$ + } + this.shrinkRightLimit = shrinkRightLimit; + + this.shrinkAbsorb = shrinkAbsorb; + this.growAbsorb = growAbsorb; + } +} diff --git a/app/src/main/java/java/awt/font/GlyphMetrics.java b/app/src/main/java/java/awt/font/GlyphMetrics.java new file mode 100644 index 000000000..287172231 --- /dev/null +++ b/app/src/main/java/java/awt/font/GlyphMetrics.java @@ -0,0 +1,266 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ + +package java.awt.font; + +import java.awt.geom.Rectangle2D; + +/** + * The GlyphMetrics class provides information about the size and shape of a + * single glyph. Each glyph has information to specify whether its baseline is + * horizontal or vertical as well as information on how it interacts with other + * characters in a text, given as one of the following types: STANDARD, + * LIGATURE, COMBINING, or COMPONENT. + * + * @since Android 1.0 + */ +public final class GlyphMetrics { + + // advance width of the glyph character cell + /** + * The advance x. + */ + private float advanceX; + + // advance height of the glyph character cell + /** + * The advance y. + */ + private float advanceY; + + // flag if the glyph horizontal + /** + * The horizontal. + */ + private boolean horizontal; + + // glyph type code + /** + * The glyph type. + */ + private byte glyphType; + + // bounding box for outline of the glyph + /** + * The bounds. + */ + private Rectangle2D.Float bounds; + + /** + * The Constant STANDARD indicates a glyph that represents a single + * character. + */ + public static final byte STANDARD = 0; + + /** + * The Constant LIGATURE indicates a glyph that represents multiple + * characters as a ligature. + */ + public static final byte LIGATURE = 1; + + /** + * The Constant COMBINING indicates a glyph which has no caret position + * between glyphs (for example umlaut). + */ + public static final byte COMBINING = 2; + + /** + * The Constant COMPONENT indicates a glyph with no corresponding character + * in the backing store. + */ + public static final byte COMPONENT = 3; + + /** + * The Constant WHITESPACE indicates a glyph without visual representation. + */ + public static final byte WHITESPACE = 4; + + /** + * Instantiates a new GlyphMetrics object with the specified parameters. + * + * @param horizontal + * specifies if metrics are for a horizontal baseline (true + * value), or a vertical baseline (false value). + * @param advanceX + * the X component of the glyph's advance. + * @param advanceY + * the Y component of the glyph's advance. + * @param bounds + * the glyph's bounds. + * @param glyphType + * the glyph's type. + */ + public GlyphMetrics(boolean horizontal, float advanceX, float advanceY, Rectangle2D bounds, + byte glyphType) { + this.horizontal = horizontal; + this.advanceX = advanceX; + this.advanceY = advanceY; + + this.bounds = new Rectangle2D.Float(); + this.bounds.setRect(bounds); + + this.glyphType = glyphType; + } + + /** + * Instantiates a new horizontal GlyphMetrics with the specified parameters. + * + * @param advanceX + * the X component of the glyph's advance. + * @param bounds + * the glyph's bounds. + * @param glyphType + * the glyph's type. + */ + public GlyphMetrics(float advanceX, Rectangle2D bounds, byte glyphType) { + this.advanceX = advanceX; + this.advanceY = 0; + + this.horizontal = true; + + this.bounds = new Rectangle2D.Float(); + this.bounds.setRect(bounds); + + this.glyphType = glyphType; + } + + /** + * Gets the glyph's bounds. + * + * @return glyph's bounds. + */ + public Rectangle2D getBounds2D() { + return (Rectangle2D.Float)this.bounds.clone(); + } + + /** + * Checks if this glyph is whitespace or not. + * + * @return true, if this glyph is whitespace, false otherwise. + */ + public boolean isWhitespace() { + return ((this.glyphType & 4) == WHITESPACE); + } + + /** + * Checks if this glyph is standard or not. + * + * @return true, if this glyph is standard, false otherwise. + */ + public boolean isStandard() { + return ((this.glyphType & 3) == STANDARD); + } + + /** + * Checks if this glyph is ligature or not. + * + * @return true, if this glyph is ligature, false otherwise. + */ + public boolean isLigature() { + return ((this.glyphType & 3) == LIGATURE); + } + + /** + * Checks if this glyph is component or not. + * + * @return true, if this glyph is component, false otherwise. + */ + public boolean isComponent() { + return ((this.glyphType & 3) == COMPONENT); + } + + /** + * Checks if this glyph is combining or not. + * + * @return true, if this glyph is combining, false otherwise. + */ + public boolean isCombining() { + return ((this.glyphType & 3) == COMBINING); + } + + /** + * Gets the glyph's type. + * + * @return the glyph's type. + */ + public int getType() { + return this.glyphType; + } + + /** + * Gets the distance from the right (for horizontal) or bottom (for + * vertical) of the glyph bounds to the advance. + * + * @return the distance from the right (for horizontal) or bottom (for + * vertical) of the glyph bounds to the advance. + */ + public float getRSB() { + if (this.horizontal) { + return this.advanceX - this.bounds.x - (float)this.bounds.getWidth(); + } + return this.advanceY - this.bounds.y - (float)this.bounds.getHeight(); + } + + /** + * Gets the distance from 0, 0 to the left (for horizontal) or top (for + * vertical) of the glyph bounds. + * + * @return the distance from 0, 0 to the left (for horizontal) or top (for + * vertical) of the glyph bounds. + */ + public float getLSB() { + if (this.horizontal) { + return this.bounds.x; + } + return this.bounds.y; + } + + /** + * Gets the Y component of the glyph's advance. + * + * @return the Y component of the glyph's advance. + */ + public float getAdvanceY() { + return this.advanceY; + } + + /** + * Gets the X component of the glyph's advance. + * + * @return the X component of the glyph's advance. + */ + public float getAdvanceX() { + return this.advanceX; + } + + /** + * Gets the glyph's advance along the baseline. + * + * @return the glyph's advance. + */ + public float getAdvance() { + if (this.horizontal) { + return this.advanceX; + } + return this.advanceY; + } + +} diff --git a/app/src/main/java/java/awt/font/GlyphVector.java b/app/src/main/java/java/awt/font/GlyphVector.java new file mode 100644 index 000000000..a72b774bf --- /dev/null +++ b/app/src/main/java/java/awt/font/GlyphVector.java @@ -0,0 +1,403 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ + +package java.awt.font; + +import java.awt.Font; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphJustificationInfo; +import java.awt.font.GlyphMetrics; + +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +/** + * The GlyphVector class contains a collection of glyphs with geometric + * information and each glyph's location. Each GlyphVector can be associated + * with only one Font. GlyphVector contains the following properties for each + * glyph: + *
    + *
  • the glyph position;
  • + *
  • the transform of the glyph;
  • + *
  • the metrics of the glyph in the context of the GlyphVector.
  • + *
+ * + * @since Android 1.0 + */ +public abstract class GlyphVector implements Cloneable { + + /** + * The Constant FLAG_HAS_TRANSFORMS indicates that this GlyphVector has + * per-glyph transforms. + */ + public static final int FLAG_HAS_TRANSFORMS = 1; + + /** + * The Constant FLAG_HAS_POSITION_ADJUSTMENTS indicates that the GlyphVector + * has per-glyph position adjustments. + */ + public static final int FLAG_HAS_POSITION_ADJUSTMENTS = 2; + + /** + * The Constant FLAG_RUN_RTL indicates that this GlyphVector has a right to + * left run direction. + */ + public static final int FLAG_RUN_RTL = 4; + + /** + * The Constant FLAG_COMPLEX_GLYPHS indicates that this GlyphVector has a + * complex glyph to char mapping. + */ + public static final int FLAG_COMPLEX_GLYPHS = 8; + + /** + * The Constant FLAG_MASK indicates a mask for supported flags from + * getLayoutFlags. + */ + public static final int FLAG_MASK = 15; // (|) mask of other flags + + /** + * Instantiates a new GlyphVector. + */ + public GlyphVector() { + } + + /** + * Gets the pixel bounds of the GlyphVector when rendered at the specified + * location with the specified FontRenderContext. + * + * @param frc + * the FontRenderContext. + * @param x + * the X coordinate of the GlyphVector's location. + * @param y + * the Y coordinate of the GlyphVector's location. + * @return the pixel bounds + */ + public Rectangle getPixelBounds(FontRenderContext frc, float x, float y) { + // default implementation - integer Rectangle, that encloses visual + // bounds rectangle + Rectangle2D visualRect = getVisualBounds(); + + int minX = (int)Math.floor(visualRect.getMinX() + x); + int minY = (int)Math.floor(visualRect.getMinY() + y); + int width = (int)Math.ceil(visualRect.getMaxX() + x) - minX; + int height = (int)Math.ceil(visualRect.getMaxY() + y) - minY; + + return new Rectangle(minX, minY, width, height); + } + + /** + * Gets the pixel bounds of the glyph with the specified index in this + * GlyphVector which is rendered with the specified FontRenderContext at the + * specified location. + * + * @param index + * the glyph index in this GlyphVector. + * @param frc + * the FontRenderContext. + * @param x + * the X coordinate of the GlyphVector's location. + * @param y + * the Y coordinate of the GlyphVector's location. + * @return a Rectangle bounds. + */ + public Rectangle getGlyphPixelBounds(int index, FontRenderContext frc, float x, float y) { + Rectangle2D visualRect = getGlyphVisualBounds(index).getBounds2D(); + + int minX = (int)Math.floor(visualRect.getMinX() + x); + int minY = (int)Math.floor(visualRect.getMinY() + y); + int width = (int)Math.ceil(visualRect.getMaxX() + x) - minX; + int height = (int)Math.ceil(visualRect.getMaxY() + y) - minY; + + return new Rectangle(minX, minY, width, height); + } + + /** + * Gets the visual bounds of the GlyphVector. + * + * @return the visual bounds of the GlyphVector. + */ + public abstract Rectangle2D getVisualBounds(); + + /** + * Gets the logical bounds of the GlyphVector. + * + * @return the logical bounds of the GlyphVector. + */ + public abstract Rectangle2D getLogicalBounds(); + + /** + * Sets the position of the specified glyph in this GlyphVector. + * + * @param glyphIndex + * the glyph index in this GlyphVector. + * @param newPos + * the new position of the glyph at the specified glyphIndex. + */ + public abstract void setGlyphPosition(int glyphIndex, Point2D newPos); + + /** + * Gets the position of the specified glyph in this GlyphVector. + * + * @param glyphIndex + * the glyph index in this GlyphVector. + * @return the position of the specified glyph in this GlyphVector. + */ + public abstract Point2D getGlyphPosition(int glyphIndex); + + /** + * Sets the affine transform to a glyph with the specified index in this + * GlyphVector. + * + * @param glyphIndex + * the glyth index in this GlyphVector. + * @param trans + * the AffineTransform to be assigned to the specified glyph. + */ + public abstract void setGlyphTransform(int glyphIndex, AffineTransform trans); + + /** + * Gets the transform of the specified glyph in this GlyphVector. + * + * @param glyphIndex + * the glyph index in this GlyphVector. + * @return the new transform of the glyph. + */ + public abstract AffineTransform getGlyphTransform(int glyphIndex); + + /** + * Compares this GlyphVector with the specified GlyphVector objects. + * + * @param glyphVector + * the GlyphVector object to be compared. + * @return true, if this GlyphVector is equal to the specified GlyphVector + * object, false otherwise. + */ + public abstract boolean equals(GlyphVector glyphVector); + + /** + * Gets the metrics of the glyph with the specified index in this + * GlyphVector. + * + * @param glyphIndex + * index in this GlyphVector. + * @return the metrics of the glyph with the specified index in this + * GlyphVector. + */ + public abstract GlyphMetrics getGlyphMetrics(int glyphIndex); + + /** + * Gets the justification information of the glyph whose index is specified. + * + * @param glyphIndex + * the glyph index. + * @return the GlyphJustificationInfo for the specified glyph. + */ + public abstract GlyphJustificationInfo getGlyphJustificationInfo(int glyphIndex); + + /** + * Gets the FontRenderContext of this GlyphVector. + * + * @return the FontRenderContext of this GlyphVector. + */ + public abstract FontRenderContext getFontRenderContext(); + + /** + * Gets a Shape object which defines the visual representation of the + * specified glyph in this GlyphVector, translated a distance of x in the X + * direction and y in the Y direction. + * + * @param glyphIndex + * the glyth index in this GlyphVector. + * @param x + * the distance in the X direction to translate the shape object + * before returning it. + * @param y + * the distance in the Y direction to translate the shape object + * before returning it. + * @return a Shape object which represents the visual representation of the + * specified glyph in this GlyphVector - glyph outline. + */ + public Shape getGlyphOutline(int glyphIndex, float x, float y) { + Shape initialShape = getGlyphOutline(glyphIndex); + AffineTransform trans = AffineTransform.getTranslateInstance(x, y); + return trans.createTransformedShape(initialShape); + } + + /** + * Gets the visual bounds of the specified glyph in the GlyphVector. + * + * @param glyphIndex + * the glyph index in this GlyphVector. + * @return the glyph visual bounds of the glyph with the specified index in + * the GlyphVector. + */ + public abstract Shape getGlyphVisualBounds(int glyphIndex); + + /** + * Gets a Shape object which defines the visual representation of the + * specified glyph in this GlyphVector. + * + * @param glyphIndex + * the glyth index in this GlyphVector. + * @return a Shape object which represents the visual representation of the + * specified glyph in this GlyphVector - glyph outline. + */ + public abstract Shape getGlyphOutline(int glyphIndex); + + /** + * Gets the logical bounds of the specified glyph in the GlyphVector. + * + * @param glyphIndex + * the index in this GlyphVector of the glyph from which to + * retrieve its logical bounds + * @return the logical bounds of the specified glyph in the GlyphVector. + */ + public abstract Shape getGlyphLogicalBounds(int glyphIndex); + + /** + * Gets the visual representation of this GlyphVector rendered in x, y + * location as a Shape object. + * + * @param x + * the x coordinate of the GlyphVector. + * @param y + * the y coordinate of the GlyphVector. + * @return the visual representation of this GlyphVector as a Shape object. + */ + public abstract Shape getOutline(float x, float y); + + /** + * Gets the visual representation of this GlyphVector as a Shape object. + * + * @return the visual representation of this GlyphVector as a Shape object. + */ + public abstract Shape getOutline(); + + /** + * Gets the font of this GlyphVector. + * + * @return the font of this GlyphVector. + */ + public abstract Font getFont(); + + /** + * Gets an array of the glyph codes of the specified glyphs. + * + * @param beginGlyphIndex + * the index into this GlyphVector at which to start retrieving + * glyph codes. + * @param numEntries + * the number of glyph codes. + * @param codeReturn + * the array into which the resulting glyphcodes will be written. + * @return the array of the glyph codes. + */ + public abstract int[] getGlyphCodes(int beginGlyphIndex, int numEntries, int[] codeReturn); + + /** + * Gets an array of the character indices of the specified glyphs. + * + * @param beginGlyphIndex + * the index of the first glyph to return information for. + * @param numEntries + * the number of glyph indices to return. + * @param codeReturn + * the array into which the resulting character indices will be + * written. + * @return an array of character indices for the specifies glyphs. + */ + public int[] getGlyphCharIndices(int beginGlyphIndex, int numEntries, int[] codeReturn) { + if (codeReturn == null) { + codeReturn = new int[numEntries]; + } + + for (int i = 0; i < numEntries; i++) { + codeReturn[i] = getGlyphCharIndex(i + beginGlyphIndex); + } + return codeReturn; + } + + /** + * Gets an array of the positions of the specified glyphs in this + * GlyphVector. + * + * @param beginGlyphIndex + * the index of the first glyph to return information for. + * @param numEntries + * the number of glyphs to return information for. + * @param positionReturn + * the array where the result will be stored. + * @return an array of glyph positions. + */ + public abstract float[] getGlyphPositions(int beginGlyphIndex, int numEntries, + float[] positionReturn); + + /** + * Gets the glyph code of the specified glyph. + * + * @param glyphIndex + * the index in this GlyphVector which corresponds to the glyph + * from which to retrieve the glyphcode. + * @return the glyphcode of the specified glyph. + */ + public abstract int getGlyphCode(int glyphIndex); + + /** + * Gets the first logical character's index of the specified glyph. + * + * @param glyphIndex + * the glyph index. + * @return the the first logical character's index. + */ + public int getGlyphCharIndex(int glyphIndex) { + // default implemetation one-to-one + return glyphIndex; + } + + /** + * Sets default layout to this GlyphVector. + */ + public abstract void performDefaultLayout(); + + /** + * Gets the number of glyphs in the GlyphVector. + * + * @return the number of glyphs in the GlyphVector. + */ + public abstract int getNumGlyphs(); + + /** + * Gets flags which describe the global state of the GlyphVector. The + * default implementation returns 0. + * + * @return the layout flags + */ + public int getLayoutFlags() { + // default implementation - returned value is 0 + return 0; + } + +} diff --git a/app/src/main/java/java/awt/font/GraphicAttribute.java b/app/src/main/java/java/awt/font/GraphicAttribute.java new file mode 100644 index 000000000..8480e0f6a --- /dev/null +++ b/app/src/main/java/java/awt/font/GraphicAttribute.java @@ -0,0 +1,179 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ + +package java.awt.font; + +import java.awt.Graphics2D; +import java.awt.geom.Rectangle2D; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The GraphicAttribute abstract class provides an opportunity to insert + * graphical elements in printed text. + * + * @since Android 1.0 + */ +public abstract class GraphicAttribute { + + /** + * The Constant TOP_ALIGNMENT indicates using the top line to calculate + * placement of graphics. + */ + public static final int TOP_ALIGNMENT = -1; + + /** + * The Constant BOTTOM_ALIGNMENT indicates using the bottom line to + * calculate placement of graphics. + */ + public static final int BOTTOM_ALIGNMENT = -2; + + /** + * The Constant ROMAN_BASELINE indicates the placement of the roman baseline + * with respect to the graphics origin. + */ + public static final int ROMAN_BASELINE = 0; + + /** + * The Constant CENTER_BASELINE indicates the placement of the center + * baseline with respect to the graphics origin. + */ + public static final int CENTER_BASELINE = 1; + + /** + * The Constant HANGING_BASELINE indicates the placement of the hanging + * baseline with respect to the graphics origin. + */ + public static final int HANGING_BASELINE = 2; + + // the alignment of this GraphicAttribute + /** + * The alignment. + */ + private int alignment; + + /** + * Instantiates a new graphic attribute with the specified alignment. + * + * @param align + * the specified alignment. + */ + protected GraphicAttribute(int align) { + if ((align < BOTTOM_ALIGNMENT) || (align > HANGING_BASELINE)) { + // awt.198=Illegal alignment argument + throw new IllegalArgumentException(Messages.getString("awt.198")); //$NON-NLS-1$ + } + this.alignment = align; + } + + /** + * Draws the GraphicAttribute at the specified location. + * + * @param graphics + * the Graphics. + * @param x + * the X coordinate of GraphicAttribute location. + * @param y + * the Y coordinate of GraphicAttribute location. + */ + public abstract void draw(Graphics2D graphics, float x, float y); + + /** + * Gets the GraphicAttribute's advance. It's the distance from the point at + * which the graphic is rendered and the point where the next character or + * graphic is rendered. + * + * @return the GraphicAttribute's advance. + */ + public abstract float getAdvance(); + + /** + * Gets the alignment of this GraphicAttribute. + * + * @return the alignment of this GraphicAttribute. + */ + public final int getAlignment() { + return this.alignment; + } + + /** + * Gets the ascent of this GraphicAttribute. + * + * @return the ascent of this GraphicAttribute. + */ + public abstract float getAscent(); + + /** + * Gets the bounds of this GraphicAttribute. + * + * @return the bounds of this GraphicAttribute. + */ + public Rectangle2D getBounds() { + float ascent = getAscent(); + float advance = getAdvance(); + float descent = getDescent(); + + // Default implementation - see API documentation. + return new Rectangle2D.Float(0, -ascent, advance, ascent + descent); + } + + /** + * Gets the descent of this GraphicAttribute. + * + * @return the descent of this GraphicAttribute. + */ + public abstract float getDescent(); + + /** + * Gets the GlyphJustificationInfo of this GraphicAttribute. + * + * @return the GlyphJustificationInfo of this GraphicAttribute. + */ + public GlyphJustificationInfo getJustificationInfo() { + + /* + * Default implementation. Since documentation doesn't describe default + * values, they were calculated based on 1.5 release behavior and can be + * obtained using next test sample: // Create GraphicAttribute class + * implementation public class MyGraphicAttribute extends + * GraphicAttribute { protected MyGraphicAttribute(int align) { + * super(align); } public float getDescent() { return 0; } public float + * getAdvance() { return 1; } public void draw(Graphics2D g2, float x, + * float y) { } public float getAscent() { return 0; } } + * MyGraphicAttribute myGA = gat.new MyGraphicAttribute(0); // print + * justification parameters + * System.out.println(myGA.getJustificationInfo().growAbsorb); + * System.out.println(myGA.getJustificationInfo().shrinkAbsorb); + * System.out.println(myGA.getJustificationInfo().growLeftLimit); + * System.out.println(myGA.getJustificationInfo().growPriority); + * System.out.println(myGA.getJustificationInfo().growRightLimit); + * System.out.println(myGA.getJustificationInfo().shrinkLeftLimit); + * System.out.println(myGA.getJustificationInfo().shrinkPriority); + * System.out.println(myGA.getJustificationInfo().shrinkRightLimit); + * System.out.println(myGA.getJustificationInfo().weight); + */ + float advance = getAdvance(); + return new GlyphJustificationInfo(advance, false, + GlyphJustificationInfo.PRIORITY_INTERCHAR, advance / 3, advance / 3, false, + GlyphJustificationInfo.PRIORITY_WHITESPACE, 0, 0); + } + +} diff --git a/app/src/main/java/java/awt/font/ImageGraphicAttribute.java b/app/src/main/java/java/awt/font/ImageGraphicAttribute.java new file mode 100644 index 000000000..d6d4758d3 --- /dev/null +++ b/app/src/main/java/java/awt/font/ImageGraphicAttribute.java @@ -0,0 +1,185 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ + +package java.awt.font; + +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.geom.Rectangle2D; + +import org.apache.harmony.misc.HashCode; + +/** + * The ImageGraphicAttribute class provides an opportunity to insert images to a + * text. + * + * @since Android 1.0 + */ +public final class ImageGraphicAttribute extends GraphicAttribute { + + // Image object rendered by this ImageGraphicAttribute + /** + * The image. + */ + private Image fImage; + + // X coordinate of the origin point + /** + * The origin x. + */ + private float fOriginX; + + // Y coordinate of the origin point + /** + * The origin y. + */ + private float fOriginY; + + // the width of the image object + /** + * The img width. + */ + private float fImgWidth; + + // the height of the image object + /** + * The img height. + */ + private float fImgHeight; + + /** + * Instantiates a new ImageGraphicAttribute with the specified image, + * alignment and origins. + * + * @param image + * the Image to be rendered by ImageGraphicAttribute. + * @param alignment + * the alignment of the ImageGraphicAttribute. + * @param originX + * the origin X coordinate in the image of ImageGraphicAttribute. + * @param originY + * the origin Y coordinate in the image of ImageGraphicAttribute. + */ + public ImageGraphicAttribute(Image image, int alignment, float originX, float originY) { + super(alignment); + + this.fImage = image; + this.fOriginX = originX; + this.fOriginY = originY; + + this.fImgWidth = fImage.getWidth(null); + this.fImgHeight = fImage.getHeight(null); + + } + + /** + * Instantiates a new ImageGraphicAttribute with the specified image and + * alignment. + * + * @param image + * the Image to be rendered by ImageGraphicAttribute. + * @param alignment + * the alignment of the ImageGraphicAttribute. + */ + public ImageGraphicAttribute(Image image, int alignment) { + this(image, alignment, 0, 0); + } + + /** + * Returns a hash code of this ImageGraphicAttribute object. + * + * @return the hash code of this ImageGraphicAttribute object. + */ + @Override + public int hashCode() { + HashCode hash = new HashCode(); + + hash.append(fImage.hashCode()); + hash.append(getAlignment()); + return hash.hashCode(); + } + + /** + * Compares the specified ImageGraphicAttribute object with this + * ImageGraphicAttribute object. + * + * @param iga + * the ImageGraphicAttribute object to be compared. + * @return true, if the specified ImageGraphicAttribute object is equal to + * this ImageGraphicAttribute object, false otherwise. + */ + public boolean equals(ImageGraphicAttribute iga) { + if (iga == null) { + return false; + } + + if (iga == this) { + return true; + } + + return (fOriginX == iga.fOriginX && fOriginY == iga.fOriginY + && getAlignment() == iga.getAlignment() && fImage.equals(iga.fImage)); + } + + /** + * Compares the specified Object with this ImageGraphicAttribute object. + * + * @param obj + * the Object to be compared. + * @return true, if the specified Object is equal to this + * ImageGraphicAttribute object, false otherwise. + */ + @Override + public boolean equals(Object obj) { + try { + return equals((ImageGraphicAttribute)obj); + } catch (ClassCastException e) { + return false; + } + + } + + @Override + public void draw(Graphics2D g2, float x, float y) { + g2.drawImage(fImage, (int)(x - fOriginX), (int)(y - fOriginY), null); + } + + @Override + public float getAdvance() { + return Math.max(0, fImgWidth - fOriginX); + } + + @Override + public float getAscent() { + return Math.max(0, fOriginY); + } + + @Override + public Rectangle2D getBounds() { + return new Rectangle2D.Float(-fOriginX, -fOriginY, fImgWidth, fImgHeight); + } + + @Override + public float getDescent() { + return Math.max(0, fImgHeight - fOriginY); + } + +} diff --git a/app/src/main/java/java/awt/font/LineBreakMeasurer.java b/app/src/main/java/java/awt/font/LineBreakMeasurer.java new file mode 100644 index 000000000..4800093f6 --- /dev/null +++ b/app/src/main/java/java/awt/font/LineBreakMeasurer.java @@ -0,0 +1,238 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @author Oleg V. Khaschansky + * @version $Revision$ + */ + +package java.awt.font; + +import java.text.AttributedCharacterIterator; //???AWT: import java.text.BreakIterator; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The class LineBreakMeasurer provides methods to measure the graphical + * representation of a text in order to determine where to add line breaks so + * the resulting line of text fits its wrapping width. The wrapping width + * defines the visual width of the paragraph. + * + * @since Android 1.0 + */ +public final class LineBreakMeasurer { + + /** + * The tm. + */ + private TextMeasurer tm = null; + + // ???AWT private BreakIterator bi = null; + /** + * The position. + */ + private int position = 0; + + /** + * The maxpos. + */ + int maxpos = 0; + + /** + * Instantiates a new LineBreakMeasurer object for the specified text. + * + * @param text + * the AttributedCharacterIterator object which contains text + * with at least one character. + * @param frc + * the FontRenderContext represented information about graphic + * device. + */ + public LineBreakMeasurer(AttributedCharacterIterator text, FontRenderContext frc) { + // ???AWT: this(text, BreakIterator.getLineInstance(), frc); + } + + /* + * ???AWT public LineBreakMeasurer( AttributedCharacterIterator text, + * BreakIterator bi, FontRenderContext frc ) { tm = new TextMeasurer(text, + * frc); this.bi = bi; this.bi.setText(text); position = + * text.getBeginIndex(); maxpos = tm.aci.getEndIndex(); } + */ + + /** + * Deletes a character from the specified position of the text, updates this + * LineBreakMeasurer object. + * + * @param newText + * the new text. + * @param pos + * the position of the character which is deleted. + */ + public void deleteChar(AttributedCharacterIterator newText, int pos) { + tm.deleteChar(newText, pos); + // ???AWT: bi.setText(newText); + + position = newText.getBeginIndex(); + + maxpos--; + } + + /** + * Gets current position of this LineBreakMeasurer. + * + * @return the current position of this LineBreakMeasurer + */ + public int getPosition() { + return position; + } + + /** + * Inserts a character at the specified position in the text, updates this + * LineBreakMeasurer object. + * + * @param newText + * the new text. + * @param pos + * the position of the character which is inserted. + */ + public void insertChar(AttributedCharacterIterator newText, int pos) { + tm.insertChar(newText, pos); + // ???AWT: bi.setText(newText); + + position = newText.getBeginIndex(); + + maxpos++; + } + + /** + * Returns the next line of text, updates current position in this + * LineBreakMeasurer. + * + * @param wrappingWidth + * the maximum visible line width. + * @param offsetLimit + * the limit point within the text indicating that no further + * text should be included on the line; the paragraph break. + * @param requireNextWord + * if true, null is returned (the entire word at the current + * position does not fit within the wrapping width); if false, a + * valid layout is returned that includes at least the character + * at the current position. + * @return the next TextLayout which begins at the current position and + * represents the next line of text with width wrappingWidth, null + * is returned if the entire word at the current position does not + * fit within the wrapping width. + */ + public TextLayout nextLayout(float wrappingWidth, int offsetLimit, boolean requireNextWord) { + if (position == maxpos) { + return null; + } + + int nextPosition = nextOffset(wrappingWidth, offsetLimit, requireNextWord); + + if (nextPosition == position) { + return null; + } + TextLayout layout = tm.getLayout(position, nextPosition); + position = nextPosition; + return layout; + } + + /** + * Returns the next line of text. + * + * @param wrappingWidth + * the maximum visible line width. + * @return the next line of text. + */ + public TextLayout nextLayout(float wrappingWidth) { + return nextLayout(wrappingWidth, maxpos, false); + } + + /** + * Returns the end position of the next line of text. + * + * @param wrappingWidth + * the maximum visible line width. + * @return the end position of the next line of text. + */ + public int nextOffset(float wrappingWidth) { + return nextOffset(wrappingWidth, maxpos, false); + } + + /** + * Returns the end position of the next line of text. + * + * @param wrappingWidth + * the maximum visible line width. + * @param offsetLimit + * the limit point withing the text indicating that no further + * text should be included on the line; the paragraph break. + * @param requireNextWord + * if true, the current position is returned if the entire next + * word does not fit within wrappingWidth; if false, the offset + * returned is at least one greater than the current position. + * @return the end position of the next line of text. + * @throws IllegalArgumentException + * if the offsetLimit is less than the current position. + */ + public int nextOffset(float wrappingWidth, int offsetLimit, boolean requireNextWord) { + if (offsetLimit <= position) { + // awt.203=Offset limit should be greater than current position. + throw new IllegalArgumentException(Messages.getString("awt.203")); //$NON-NLS-1$ + } + + if (position == maxpos) { + return position; + } + + int breakPos = tm.getLineBreakIndex(position, wrappingWidth); + int correctedPos = breakPos; + + // This check is required because bi.preceding(maxpos) throws an + // exception + /* + * ???AWT if (breakPos == maxpos) { correctedPos = maxpos; } else if + * (Character.isWhitespace(bi.getText().setIndex(breakPos))) { + * correctedPos = bi.following(breakPos); } else { correctedPos = + * bi.preceding(breakPos); } + */ + + if (position >= correctedPos) { + if (requireNextWord) { + correctedPos = position; + } else { + correctedPos = Math.max(position + 1, breakPos); + } + } + + return Math.min(correctedPos, offsetLimit); + } + + /** + * Sets the new position of this LineBreakMeasurer. + * + * @param pos + * the new position of this LineBreakMeasurer. + */ + public void setPosition(int pos) { + if (tm.aci.getBeginIndex() > pos || maxpos < pos) { + // awt.33=index is out of range + throw new IllegalArgumentException(Messages.getString("awt.33")); //$NON-NLS-1$ + } + position = pos; + } +} diff --git a/app/src/main/java/java/awt/font/LineMetrics.java b/app/src/main/java/java/awt/font/LineMetrics.java new file mode 100644 index 000000000..4b03e5db2 --- /dev/null +++ b/app/src/main/java/java/awt/font/LineMetrics.java @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ + +package java.awt.font; + +/** + * The LineMetrics class provides information such as concerning how the text is + * positioned with respect to the base line, such as ascent, descent, and + * leading. + * + * @since Android 1.0 + */ +public abstract class LineMetrics { + + /** + * Gets the baseline offsets of the text according to the the baseline of + * this text. + * + * @return the baseline offsets of the text according to the the baseline of + * this text. + */ + public abstract float[] getBaselineOffsets(); + + /** + * Gets the number of characters of the text. + * + * @return the number of characters of the text. + */ + public abstract int getNumChars(); + + /** + * Gets the baseline index, returns one of the following index: + * ROMAN_BASELINE, CENTER_BASELINE, HANGING_BASELINE. + * + * @return the baseline index: ROMAN_BASELINE, CENTER_BASELINE or + * HANGING_BASELINE. + */ + public abstract int getBaselineIndex(); + + /** + * Gets the thickness of the underline. + * + * @return the thickness of the underline. + */ + public abstract float getUnderlineThickness(); + + /** + * Gets the offset of the underline. + * + * @return the offset of the underline. + */ + public abstract float getUnderlineOffset(); + + /** + * Gets the thickness of strike through line. + * + * @return the thickness of strike through line. + */ + public abstract float getStrikethroughThickness(); + + /** + * Gets the offset of the strike through line. + * + * @return the offset of the strike through line. + */ + public abstract float getStrikethroughOffset(); + + /** + * Gets the leading of the text. + * + * @return the leading of the text. + */ + public abstract float getLeading(); + + /** + * Gets the height of the text as a sum of the ascent, the descent and the + * leading. + * + * @return the height of the text as a sum of the ascent, the descent and + * the leading. + */ + public abstract float getHeight(); + + /** + * Gets the descent of the text. + * + * @return the descent of the text. + */ + public abstract float getDescent(); + + /** + * Gets the ascent of the text. + * + * @return the ascent of the text. + */ + public abstract float getAscent(); + +} diff --git a/app/src/main/java/java/awt/font/MultipleMaster.java b/app/src/main/java/java/awt/font/MultipleMaster.java new file mode 100644 index 000000000..d264f2483 --- /dev/null +++ b/app/src/main/java/java/awt/font/MultipleMaster.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ + +package java.awt.font; + +import java.awt.Font; + +/** + * The MultipleMaster interface provides methods to manipulate MultipleMaster + * type fonts and retrieve graphical and design data from them. + * + * @since Android 1.0 + */ +public interface MultipleMaster { + + /** + * Derives a new multiple master font based on the specified parameters. + * + * @param glyphWidths + * float array which represents width of each glyph in font + * space. + * @param avgStemWidth + * the average stem width in font space. + * @param typicalCapHeight + * the typical upper case char height. + * @param typicalXHeight + * the typical lower case char height. + * @param italicAngle + * the slope angle for italics. + * @return a MultipleMaster font. + */ + public Font deriveMMFont(float[] glyphWidths, float avgStemWidth, float typicalCapHeight, + float typicalXHeight, float italicAngle); + + /** + * Derives a new multiple master font based on the design axis values + * contained in the specified array. + * + * @param axes + * an float array which contains axis values. + * @return a MultipleMaster font. + */ + public Font deriveMMFont(float[] axes); + + /** + * Gets default design values for the axes. + * + * @return the default design values for the axes. + */ + public float[] getDesignAxisDefaults(); + + /** + * Gets the array of design axis names. + * + * @return the array of design axis names. + */ + public String[] getDesignAxisNames(); + + /** + * Gets the array of design axis ranges. + * + * @return the array of design axis ranges. + */ + public float[] getDesignAxisRanges(); + + /** + * Gets the number of multiple master design controls. + * + * @return the number of multiple master design controls. + */ + public int getNumDesignAxes(); + +} diff --git a/app/src/main/java/java/awt/font/OpenType.java b/app/src/main/java/java/awt/font/OpenType.java new file mode 100644 index 000000000..db66911c4 --- /dev/null +++ b/app/src/main/java/java/awt/font/OpenType.java @@ -0,0 +1,418 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ + +package java.awt.font; + +/** + * The OpenType interface provides constants and methods for getting instance + * data for fonts of type OpenType and TrueType. For more information, see the + * + * OpenType specification. + * + * @since Android 1.0 + */ +public interface OpenType { + + /** + * The Constant TAG_ACNT indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_ACNT = 1633906292; + + /** + * The Constant TAG_AVAR indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_AVAR = 1635148146; + + /** + * The Constant TAG_BASE indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_BASE = 1111577413; + + /** + * The Constant TAG_BDAT indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_BDAT = 1650745716; + + /** + * The Constant TAG_BLOC indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_BLOC = 1651273571; + + /** + * The Constant TAG_BSLN indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_BSLN = 1651731566; + + /** + * The Constant TAG_CFF indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_CFF = 1128678944; + + /** + * The Constant TAG_CMAP indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_CMAP = 1668112752; + + /** + * The Constant TAG_CVAR indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_CVAR = 1668702578; + + /** + * The Constant TAG_CVT indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_CVT = 1668707360; + + /** + * The Constant TAG_DSIG indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_DSIG = 1146308935; + + /** + * The Constant TAG_EBDT indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_EBDT = 1161970772; + + /** + * The Constant TAG_EBLC indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_EBLC = 1161972803; + + /** + * The Constant TAG_EBSC indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_EBSC = 1161974595; + + /** + * The Constant TAG_FDSC indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_FDSC = 1717859171; + + /** + * The Constant TAG_FEAT indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_FEAT = 1717920116; + + /** + * The Constant TAG_FMTX indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_FMTX = 1718449272; + + /** + * The Constant TAG_FPGM indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_FPGM = 1718642541; + + /** + * The Constant TAG_FVAR indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_FVAR = 1719034226; + + /** + * The Constant TAG_GASP indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_GASP = 1734439792; + + /** + * The Constant TAG_GDEF indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_GDEF = 1195656518; + + /** + * The Constant TAG_GLYF indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_GLYF = 1735162214; + + /** + * The Constant TAG_GPOS indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_GPOS = 1196445523; + + /** + * The Constant TAG_GSUB indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_GSUB = 1196643650; + + /** + * The Constant TAG_GVAR indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_GVAR = 1735811442; + + /** + * The Constant TAG_HDMX indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_HDMX = 1751412088; + + /** + * The Constant TAG_HEAD indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_HEAD = 1751474532; + + /** + * The Constant TAG_HHEA indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_HHEA = 1751672161; + + /** + * The Constant TAG_HMTX indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_HMTX = 1752003704; + + /** + * The Constant TAG_JSTF indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_JSTF = 1246975046; + + /** + * The Constant TAG_JUST indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_JUST = 1786082164; + + /** + * The Constant TAG_KERN indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_KERN = 1801810542; + + /** + * The Constant TAG_LCAR indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_LCAR = 1818452338; + + /** + * The Constant TAG_LOCA indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_LOCA = 1819239265; + + /** + * The Constant TAG_LTSH indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_LTSH = 1280594760; + + /** + * The Constant TAG_MAXP indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_MAXP = 1835104368; + + /** + * The Constant TAG_MMFX indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_MMFX = 1296909912; + + /** + * The Constant TAG_MMSD indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_MMSD = 1296913220; + + /** + * The Constant TAG_MORT indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_MORT = 1836020340; + + /** + * The Constant TAG_NAME indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_NAME = 1851878757; + + /** + * The Constant TAG_OPBD indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_OPBD = 1836020340; + + /** + * The Constant TAG_OS2 indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_OS2 = 1330851634; + + /** + * The Constant TAG_PCLT indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_PCLT = 1346587732; + + /** + * The Constant TAG_POST indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_POST = 1886352244; + + /** + * The Constant TAG_PREP indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_PREP = 1886545264; + + /** + * The Constant TAG_PROP indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_PROP = 1886547824; + + /** + * The Constant TAG_TRAK indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_TRAK = 1953653099; + + /** + * The Constant TAG_TYP1 indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_TYP1 = 1954115633; + + /** + * The Constant TAG_VDMX indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_VDMX = 1447316824; + + /** + * The Constant TAG_VHEA indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_VHEA = 1986553185; + + /** + * The Constant TAG_VMTX indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_VMTX = 1986884728; + + /** + * Returns the OpenType font version. + * + * @return the the OpenType font version. + */ + public int getVersion(); + + /** + * Gets the table for a specified tag. Sfnt tables include cmap, name and + * head items. + * + * @param sfntTag + * the sfnt tag. + * @return a byte array contains the font data corresponding to the + * specified tag. + */ + public byte[] getFontTable(int sfntTag); + + /** + * Gets the table for a specified tag. Sfnt tables include cmap, name and + * head items. + * + * @param sfntTag + * the sfnt tag. + * @param offset + * the offset of the returned table. + * @param count + * the number of returned table. + * @return the table corresponding to sfntTag and containing the bytes + * starting at offset byte and including count bytes. + */ + public byte[] getFontTable(int sfntTag, int offset, int count); + + /** + * Gets the table for a specified tag. Sfnt tables include cmap, name and + * head items. + * + * @param strSfntTag + * the str sfnt tag as a String. + * @return a byte array contains the font data corresponding to the + * specified tag. + */ + public byte[] getFontTable(String strSfntTag); + + /** + * Gets the table for a specified tag. Sfnt tables include cmap, name and + * head items. + * + * @param strSfntTag + * the sfnt tag as a String. + * @param offset + * the offset of the returned table. + * @param count + * the number of returned table. + * @return the table corresponding to sfntTag and containing the bytes + * starting at offset byte and including count bytes. + */ + public byte[] getFontTable(String strSfntTag, int offset, int count); + + /** + * Gets the table size for a specified tag. + * + * @param strSfntTag + * the sfnt tag as a String. + * @return the table size for a specified tag. + */ + public int getFontTableSize(String strSfntTag); + + /** + * Gets the table size for a specified tag. + * + * @param sfntTag + * the sfnt tag. + * @return the table size for a specified tag. + */ + public int getFontTableSize(int sfntTag); + +} diff --git a/app/src/main/java/java/awt/font/ShapeGraphicAttribute.java b/app/src/main/java/java/awt/font/ShapeGraphicAttribute.java new file mode 100644 index 000000000..182bffddc --- /dev/null +++ b/app/src/main/java/java/awt/font/ShapeGraphicAttribute.java @@ -0,0 +1,206 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ + +package java.awt.font; + +import java.awt.BasicStroke; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; + +import org.apache.harmony.misc.HashCode; + +/** + * The ShapeGraphicAttribute class provides an opportunity to insert shapes to a + * text. + * + * @since Android 1.0 + */ +public final class ShapeGraphicAttribute extends GraphicAttribute { + + // shape to render + /** + * The shape. + */ + private Shape fShape; + + // flag, if the shape should be stroked (true) or filled (false) + /** + * The stroke. + */ + private boolean fStroke; + + // bounds of the shape + /** + * The bounds. + */ + private Rectangle2D fBounds; + + // X coordinate of the origin point + /** + * The origin x. + */ + private float fOriginX; + + // Y coordinate of the origin point + /** + * The origin y. + */ + private float fOriginY; + + // width of the shape + /** + * The shape width. + */ + private float fShapeWidth; + + // height of the shape + /** + * The shape height. + */ + private float fShapeHeight; + + /** + * The Constant STROKE indicates whether the Shape is stroked or not. + */ + public static final boolean STROKE = true; + + /** + * The Constant FILL indicates whether the Shape is filled or not. + */ + public static final boolean FILL = false; + + /** + * Instantiates a new ShapeGraphicAttribute object for the specified Shape. + * + * @param shape + * the shape to be rendered by this ShapeGraphicAttribute. + * @param alignment + * the alignment of this ShapeGraphicAttribute. + * @param stroke + * true if the Shape is stroked, false if the Shape is filled. + */ + public ShapeGraphicAttribute(Shape shape, int alignment, boolean stroke) { + super(alignment); + + this.fShape = shape; + this.fStroke = stroke; + + this.fBounds = fShape.getBounds2D(); + + this.fOriginX = (float)fBounds.getMinX(); + this.fOriginY = (float)fBounds.getMinY(); + + this.fShapeWidth = (float)fBounds.getWidth(); + this.fShapeHeight = (float)fBounds.getHeight(); + } + + /** + * Returns a hash code of this ShapeGraphicAttribute object. + * + * @return a hash code of this ShapeGraphicAttribute object. + */ + @Override + public int hashCode() { + HashCode hash = new HashCode(); + + hash.append(fShape.hashCode()); + hash.append(getAlignment()); + return hash.hashCode(); + } + + /** + * Compares this ShapeGraphicAttribute object to the specified + * ShapeGraphicAttribute object. + * + * @param sga + * the ShapeGraphicAttribute object to be compared. + * @return true, if this ShapeGraphicAttribute object is equal to the + * specified ShapeGraphicAttribute object, false otherwise. + */ + public boolean equals(ShapeGraphicAttribute sga) { + if (sga == null) { + return false; + } + + if (sga == this) { + return true; + } + + return (fStroke == sga.fStroke && getAlignment() == sga.getAlignment() && fShape + .equals(sga.fShape)); + + } + + /** + * Compares this ShapeGraphicAttribute object to the specified Object. + * + * @param obj + * the Object to be compared. + * @return true, if this ShapeGraphicAttribute object is equal to the + * specified Object, false otherwise. + */ + @Override + public boolean equals(Object obj) { + try { + return equals((ShapeGraphicAttribute)obj); + } catch (ClassCastException e) { + return false; + } + } + + @Override + public void draw(Graphics2D g2, float x, float y) { + AffineTransform at = AffineTransform.getTranslateInstance(x, y); + if (fStroke == STROKE) { + Stroke oldStroke = g2.getStroke(); + g2.setStroke(new BasicStroke()); + g2.draw(at.createTransformedShape(fShape)); + g2.setStroke(oldStroke); + } else { + g2.fill(at.createTransformedShape(fShape)); + } + + } + + @Override + public float getAdvance() { + return Math.max(0, fShapeWidth + fOriginX); + } + + @Override + public float getAscent() { + return Math.max(0, -fOriginY); + } + + @Override + public Rectangle2D getBounds() { + return (Rectangle2D)fBounds.clone(); + } + + @Override + public float getDescent() { + return Math.max(0, fShapeHeight + fOriginY); + } + +} diff --git a/app/src/main/java/java/awt/font/TextHitInfo.java b/app/src/main/java/java/awt/font/TextHitInfo.java new file mode 100644 index 000000000..6460ebace --- /dev/null +++ b/app/src/main/java/java/awt/font/TextHitInfo.java @@ -0,0 +1,215 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @author Oleg V. Khaschansky + * @version $Revision$ + */ + +package java.awt.font; + +import org.apache.harmony.misc.HashCode; + +/** + * The TextHitInfo class provides information about a caret position in a text + * model for insertion or deletion of a character in a text. The TextHitInfo + * defines two biases of the character: leading or trailing. Leading position + * means the left edge of the specified character (TextHitInfo.leading(2) method + * for "text" returns the left side of "x"). Trailing position means the right + * edge of the specified character (TextHitInfo.trailing(2) method for "text" + * returns the right side of "x"). + * + * @since Android 1.0 + */ +public final class TextHitInfo { + + /** + * The char idx. + */ + private int charIdx; // Represents character index in the line + + /** + * The is trailing. + */ + private boolean isTrailing; + + /** + * Instantiates a new text hit info. + * + * @param idx + * the idx. + * @param isTrailing + * the is trailing. + */ + private TextHitInfo(int idx, boolean isTrailing) { + charIdx = idx; + this.isTrailing = isTrailing; + } + + /** + * Returns the textual string representation of this TextHitInfo instance. + * + * @return the string representation. + */ + @Override + public String toString() { + return new String("TextHitInfo[" + charIdx + ", " + //$NON-NLS-1$ //$NON-NLS-2$ + (isTrailing ? "Trailing" : "Leading") + "]" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + ); + } + + /** + * Compares this TextHitInfo object with the specified object. + * + * @param obj + * the Object to be compared. + * @return true, if the specified object is a TextHitInfo object with the + * same data values as this TextHitInfo, false otherwise. + */ + @Override + public boolean equals(Object obj) { + if (obj instanceof TextHitInfo) { + return equals((TextHitInfo)obj); + } + return false; + } + + /** + * Compares this TextHitInfo object with the specified TextHitInfo object. + * + * @param thi + * the TextHitInfo object to be compared. + * @return true, if this TextHitInfo object has the same data values as the + * specified TextHitInfo object, false otherwise. + */ + public boolean equals(TextHitInfo thi) { + return thi != null && thi.charIdx == charIdx && thi.isTrailing == isTrailing; + } + + /** + * Gets a TextHitInfo object with its character index at the specified + * offset from the character index of this TextHitInfo. + * + * @param offset + * the offset. + * @return the TextHitInfo. + */ + public TextHitInfo getOffsetHit(int offset) { + return new TextHitInfo(charIdx + offset, isTrailing); + } + + /** + * Gets a TextHitInfo associated with the other side of the insertion point. + * + * @return the other hit. + */ + public TextHitInfo getOtherHit() { + return isTrailing ? new TextHitInfo(charIdx + 1, false) + : new TextHitInfo(charIdx - 1, true); + } + + /** + * Returns true if the leading edge of the character is hit, false if the + * trailing edge of the character is hit. + * + * @return true if the leading edge of the character is hit, false if the + * trailing edge of the character is hit. + */ + public boolean isLeadingEdge() { + return !isTrailing; + } + + /** + * Returns the hash code value of this TextHitInfo instance. + * + * @return the hash code value. + */ + @Override + public int hashCode() { + return HashCode.combine(charIdx, isTrailing); + } + + /** + * Gets the insertion index. + * + * @return the insertion index: character index if the leading edge is hit, + * or character index + 1 if the trailing edge is hit. + */ + public int getInsertionIndex() { + return isTrailing ? charIdx + 1 : charIdx; + } + + /** + * Gets the index of the character hit. + * + * @return the character hit's index. + */ + public int getCharIndex() { + return charIdx; + } + + /** + * Returns a TextHitInfo associated with the trailing edge of the character + * at the specified char index. + * + * @param charIndex + * the char index. + * @return the TextHitInfo associated with the trailing edge of the + * character at the specified char index. + */ + public static TextHitInfo trailing(int charIndex) { + return new TextHitInfo(charIndex, true); + } + + /** + * Returns a TextHitInfo object associated with the leading edge of the + * character at the specified char index. + * + * @param charIndex + * the char index. + * @return the TextHitInfo object associated with the leading edge of the + * character at the specified char index. + */ + public static TextHitInfo leading(int charIndex) { + return new TextHitInfo(charIndex, false); + } + + /** + * Returns a (trailing) TextHitInfo object associated with the character + * before the specified offset. + * + * @param offset + * the offset. + * @return the TextHitInfo object associated with the character before the + * specified offset. + */ + public static TextHitInfo beforeOffset(int offset) { + return new TextHitInfo(offset - 1, true); + } + + /** + * Returns a (leading) TextHitInfo object associated with the character + * after the specified offset. + * + * @param offset + * the offset. + * @return the TextHitInfo object associated with the character after the + * specified offset. + */ + public static TextHitInfo afterOffset(int offset) { + return new TextHitInfo(offset, false); + } +} diff --git a/app/src/main/java/java/awt/font/TextLayout.java b/app/src/main/java/java/awt/font/TextLayout.java new file mode 100644 index 000000000..cc6f0ba3a --- /dev/null +++ b/app/src/main/java/java/awt/font/TextLayout.java @@ -0,0 +1,927 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ + +package java.awt.font; + +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.geom.GeneralPath; +import java.text.AttributedCharacterIterator; +import java.text.AttributedString; +import java.util.Map; + +import org.apache.harmony.awt.gl.font.BasicMetrics; +import org.apache.harmony.awt.gl.font.CaretManager; +import org.apache.harmony.awt.gl.font.TextMetricsCalculator; +import org.apache.harmony.awt.gl.font.TextRunBreaker; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The TextLayout class defines the graphical representation of character data. + * This class provides method for obtaining information about cursor positioning + * and movement, split cursors for text with different directions, logical and + * visual highlighting, multiple baselines, hits, justification, ascent, + * descent, and advance, and rendering. A TextLayout object can be rendered + * using Graphics context. + * + * @since Android 1.0 + */ +public final class TextLayout implements Cloneable { + + /** + * The CaretPolicy class provides a policy for obtaining the caret location. + * The single getStrongCaret method specifies the policy. + */ + public static class CaretPolicy { + + /** + * Instantiates a new CaretPolicy. + */ + public CaretPolicy() { + // Nothing to do + } + + /** + * Returns whichever of the two specified TextHitInfo objects has the + * stronger caret (higher character level) in the specified TextLayout. + * + * @param hit1 + * the first TextHitInfo of the specified TextLayout. + * @param hit2 + * the second TextHitInfo of the specified TextLayout. + * @param layout + * the TextLayout. + * @return the TextHitInfo with the stronger caret. + */ + public TextHitInfo getStrongCaret(TextHitInfo hit1, TextHitInfo hit2, TextLayout layout) { + // Stronger hit is the one with greater level. + // If the level is same, leading edge is stronger. + + int level1 = layout.getCharacterLevel(hit1.getCharIndex()); + int level2 = layout.getCharacterLevel(hit2.getCharIndex()); + + if (level1 == level2) { + return (hit2.isLeadingEdge() && (!hit1.isLeadingEdge())) ? hit2 : hit1; + } + return level1 > level2 ? hit1 : hit2; + } + + } + + /** + * The Constant DEFAULT_CARET_POLICY indicates the default caret policy. + */ + public static final TextLayout.CaretPolicy DEFAULT_CARET_POLICY = new CaretPolicy(); + + /** + * The breaker. + */ + private TextRunBreaker breaker; + + /** + * The metrics valid. + */ + private boolean metricsValid = false; + + /** + * The tmc. + */ + private TextMetricsCalculator tmc; + + /** + * The metrics. + */ + private BasicMetrics metrics; + + /** + * The caret manager. + */ + private CaretManager caretManager; + + /** + * The justification width. + */ + float justificationWidth = -1; + + /** + * Instantiates a new TextLayout object from the specified string and Font. + * + * @param string + * the string to be displayed. + * @param font + * the font of the text. + * @param frc + * the FontRenderContext object for obtaining information about a + * graphics device. + */ + public TextLayout(String string, Font font, FontRenderContext frc) { + if (string == null) { + // awt.01='{0}' parameter is null + throw new IllegalArgumentException(Messages.getString("awt.01", "string")); //$NON-NLS-1$ //$NON-NLS-2$ + } + + if (font == null) { + // awt.01='{0}' parameter is null + throw new IllegalArgumentException(Messages.getString("awt.01", "font")); //$NON-NLS-1$ //$NON-NLS-2$ + } + + if (string.length() == 0) { + // awt.02='{0}' parameter has zero length + throw new IllegalArgumentException(Messages.getString("awt.02", "string")); //$NON-NLS-1$ //$NON-NLS-2$ + } + + AttributedString as = new AttributedString(string); + as.addAttribute(TextAttribute.FONT, font); + this.breaker = new TextRunBreaker(as.getIterator(), frc); + caretManager = new CaretManager(breaker); + } + + /** + * Instantiates a new TextLayout from the specified text and a map of + * attributes. + * + * @param string + * the string to be displayed. + * @param attributes + * the attributes to be used for obtaining the text style. + * @param frc + * the FontRenderContext object for obtaining information about a + * graphics device. + */ + public TextLayout(String string, + Map attributes, + FontRenderContext frc) { + if (string == null) { + // awt.01='{0}' parameter is null + throw new IllegalArgumentException(Messages.getString("awt.01", "string")); //$NON-NLS-1$ //$NON-NLS-2$ + } + + if (attributes == null) { + // awt.01='{0}' parameter is null + throw new IllegalArgumentException(Messages.getString("awt.01", "attributes")); //$NON-NLS-1$ //$NON-NLS-2$ + } + + if (string.length() == 0) { + // awt.02='{0}' parameter has zero length + throw new IllegalArgumentException(Messages.getString("awt.02", "string")); //$NON-NLS-1$ //$NON-NLS-2$ + } + + AttributedString as = new AttributedString(string); + as.addAttributes(attributes, 0, string.length()); + this.breaker = new TextRunBreaker(as.getIterator(), frc); + caretManager = new CaretManager(breaker); + } + + /** + * Instantiates a new TextLayout from the AttributedCharacterIterator. + * + * @param text + * the AttributedCharacterIterator. + * @param frc + * the FontRenderContext object for obtaining information about a + * graphics device. + */ + public TextLayout(AttributedCharacterIterator text, FontRenderContext frc) { + if (text == null) { + // awt.03='{0}' iterator parameter is null + throw new IllegalArgumentException(Messages.getString("awt.03", "text")); //$NON-NLS-1$ //$NON-NLS-2$ + } + + if (text.getBeginIndex() == text.getEndIndex()) { + // awt.04='{0}' iterator parameter has zero length + throw new IllegalArgumentException(Messages.getString("awt.04", "text")); //$NON-NLS-1$ //$NON-NLS-2$ + } + + this.breaker = new TextRunBreaker(text, frc); + caretManager = new CaretManager(breaker); + } + + /** + * Instantiates a new text layout. + * + * @param breaker + * the breaker. + */ + TextLayout(TextRunBreaker breaker) { + this.breaker = breaker; + caretManager = new CaretManager(this.breaker); + } + + /** + * Returns a hash code of this TextLayout object. + * + * @return a hash code of this TextLayout object. + */ + @Override + public int hashCode() { + return breaker.hashCode(); + } + + /** + * Returns a copy of this object. + * + * @return a copy of this object. + */ + @Override + protected Object clone() { + TextLayout res = new TextLayout((TextRunBreaker)breaker.clone()); + + if (justificationWidth >= 0) { + res.handleJustify(justificationWidth); + } + + return res; + } + + /** + * Compares this TextLayout object to the specified TextLayout object. + * + * @param layout + * the TextLayout object to be compared. + * @return true, if this TextLayout object is equal to the specified + * TextLayout object, false otherwise. + */ + public boolean equals(TextLayout layout) { + if (layout == null) { + return false; + } + return this.breaker.equals(layout.breaker); + } + + /** + * Compares this TextLayout object to the specified Object. + * + * @param obj + * the Object to be compared. + * @return true, if this TextLayout object is equal to the specified Object, + * false otherwise. + */ + @Override + public boolean equals(Object obj) { + return obj instanceof TextLayout ? equals((TextLayout)obj) : false; + } + + /** + * Gets the string representation for this TextLayout. + * + * @return the string representation for this TextLayout. + */ + @Override + public String toString() { // what for? + return super.toString(); + } + + /** + * Draws this TextLayout at the specified location with the specified + * Graphics2D context. + * + * @param g2d + * the Graphics2D object which renders this TextLayout. + * @param x + * the X coordinate of the TextLayout origin. + * @param y + * the Y coordinate of the TextLayout origin. + */ + public void draw(Graphics2D g2d, float x, float y) { + updateMetrics(); + breaker.drawSegments(g2d, x, y); + } + + /** + * Update metrics. + */ + private void updateMetrics() { + if (!metricsValid) { + breaker.createAllSegments(); + tmc = new TextMetricsCalculator(breaker); + metrics = tmc.createMetrics(); + metricsValid = true; + } + } + + /** + * Gets the advance of this TextLayout object. + * + * @return the advance of this TextLayout object. + */ + public float getAdvance() { + updateMetrics(); + return metrics.getAdvance(); + } + + /** + * Gets the ascent of this TextLayout object. + * + * @return the ascent of this TextLayout object. + */ + public float getAscent() { + updateMetrics(); + return metrics.getAscent(); + } + + /** + * Gets the baseline of this TextLayout object. + * + * @return the baseline of this TextLayout object. + */ + public byte getBaseline() { + updateMetrics(); + return (byte)metrics.getBaseLineIndex(); + } + + /** + * Gets the float array of offsets for the baselines which are used in this + * TextLayout. + * + * @return the float array of offsets for the baselines which are used in + * this TextLayout. + */ + public float[] getBaselineOffsets() { + updateMetrics(); + return tmc.getBaselineOffsets(); + } + + /** + * Gets the black box bounds of the characters in the specified area. The + * black box bounds is an Shape which contains all bounding boxes of all the + * glyphs of the characters between firstEndpoint and secondEndpoint + * parameters values. + * + * @param firstEndpoint + * the first point of the area. + * @param secondEndpoint + * the second point of the area. + * @return the Shape which contains black box bounds. + */ + public Shape getBlackBoxBounds(int firstEndpoint, int secondEndpoint) { + updateMetrics(); + if (firstEndpoint < secondEndpoint) { + return breaker.getBlackBoxBounds(firstEndpoint, secondEndpoint); + } + return breaker.getBlackBoxBounds(secondEndpoint, firstEndpoint); + } + + /** + * Gets the bounds of this TextLayout. + * + * @return the bounds of this TextLayout. + */ + public Rectangle2D getBounds() { + updateMetrics(); + return breaker.getVisualBounds(); + } + + /** + * Gets information about the caret of the specified TextHitInfo. + * + * @param hitInfo + * the TextHitInfo. + * @return the information about the caret of the specified TextHitInfo. + */ + public float[] getCaretInfo(TextHitInfo hitInfo) { + updateMetrics(); + return caretManager.getCaretInfo(hitInfo); + } + + /** + * Gets information about the caret of the specified TextHitInfo of a + * character in this TextLayout. + * + * @param hitInfo + * the TextHitInfo of a character in this TextLayout. + * @param bounds + * the bounds to which the caret info is constructed. + * @return the caret of the specified TextHitInfo. + */ + public float[] getCaretInfo(TextHitInfo hitInfo, Rectangle2D bounds) { + updateMetrics(); + return caretManager.getCaretInfo(hitInfo); + } + + /** + * Gets a Shape which represents the caret of the specified TextHitInfo in + * the bounds of this TextLayout. + * + * @param hitInfo + * the TextHitInfo. + * @param bounds + * the bounds to which the caret info is constructed. + * @return the Shape which represents the caret. + */ + public Shape getCaretShape(TextHitInfo hitInfo, Rectangle2D bounds) { + updateMetrics(); + return caretManager.getCaretShape(hitInfo, this); + } + + /** + * Gets a Shape which represents the caret of the specified TextHitInfo in + * the bounds of this TextLayout. + * + * @param hitInfo + * the TextHitInfo. + * @return the Shape which represents the caret. + */ + public Shape getCaretShape(TextHitInfo hitInfo) { + updateMetrics(); + return caretManager.getCaretShape(hitInfo, this); + } + + /** + * Gets two Shapes for the strong and weak carets with default caret policy + * and null bounds: the first element is the strong caret, the second is the + * weak caret or null. + * + * @param offset + * an offset in the TextLayout. + * @return an array of two Shapes corresponded to the strong and weak + * carets. + */ + public Shape[] getCaretShapes(int offset) { + return getCaretShapes(offset, null, TextLayout.DEFAULT_CARET_POLICY); + } + + /** + * Gets two Shapes for the strong and weak carets with the default caret + * policy: the first element is the strong caret, the second is the weak + * caret or null. + * + * @param offset + * an offset in the TextLayout. + * @param bounds + * the bounds to which to extend the carets. + * @return an array of two Shapes corresponded to the strong and weak + * carets. + */ + public Shape[] getCaretShapes(int offset, Rectangle2D bounds) { + return getCaretShapes(offset, bounds, TextLayout.DEFAULT_CARET_POLICY); + } + + /** + * Gets two Shapes for the strong and weak carets: the first element is the + * strong caret, the second is the weak caret or null. + * + * @param offset + * an offset in the TextLayout. + * @param bounds + * the bounds to which to extend the carets. + * @param policy + * the specified CaretPolicy. + * @return an array of two Shapes corresponded to the strong and weak + * carets. + */ + public Shape[] getCaretShapes(int offset, Rectangle2D bounds, TextLayout.CaretPolicy policy) { + if (offset < 0 || offset > breaker.getCharCount()) { + // awt.195=Offset is out of bounds + throw new IllegalArgumentException(Messages.getString("awt.195")); //$NON-NLS-1$ + } + + updateMetrics(); + return caretManager.getCaretShapes(offset, bounds, policy, this); + } + + /** + * Gets the number of characters in this TextLayout. + * + * @return the number of characters in this TextLayout. + */ + public int getCharacterCount() { + return breaker.getCharCount(); + } + + /** + * Gets the level of the character with the specified index. + * + * @param index + * the specified index of the character. + * @return the level of the character. + */ + public byte getCharacterLevel(int index) { + if (index == -1 || index == getCharacterCount()) { + return (byte)breaker.getBaseLevel(); + } + return breaker.getLevel(index); + } + + /** + * Gets the descent of this TextLayout. + * + * @return the descent of this TextLayout. + */ + public float getDescent() { + updateMetrics(); + return metrics.getDescent(); + } + + /** + * Gets the TextLayout wich is justified with the specified width related to + * this TextLayout. + * + * @param justificationWidth + * the width which is used for justification. + * @return a TextLayout justified to the specified width. + * @throws Error + * the error occures if this TextLayout has been already + * justified. + */ + public TextLayout getJustifiedLayout(float justificationWidth) throws Error { + float justification = breaker.getJustification(); + + if (justification < 0) { + // awt.196=Justification impossible, layout already justified + throw new Error(Messages.getString("awt.196")); //$NON-NLS-1$ + } else if (justification == 0) { + return this; + } + + TextLayout justifiedLayout = new TextLayout((TextRunBreaker)breaker.clone()); + justifiedLayout.handleJustify(justificationWidth); + return justifiedLayout; + } + + /** + * Gets the leading of this TextLayout. + * + * @return the leading of this TextLayout. + */ + public float getLeading() { + updateMetrics(); + return metrics.getLeading(); + } + + /** + * Gets a Shape representing the logical selection betweeen the specified + * endpoints and extended to the natural bounds of this TextLayout. + * + * @param firstEndpoint + * the first selected endpoint within the area of characters + * @param secondEndpoint + * the second selected endpoint within the area of characters + * @return a Shape represented the logical selection betweeen the specified + * endpoints. + */ + public Shape getLogicalHighlightShape(int firstEndpoint, int secondEndpoint) { + updateMetrics(); + return getLogicalHighlightShape(firstEndpoint, secondEndpoint, breaker.getLogicalBounds()); + } + + /** + * Gets a Shape representing the logical selection betweeen the specified + * endpoints and extended to the specified bounds of this TextLayout. + * + * @param firstEndpoint + * the first selected endpoint within the area of characters + * @param secondEndpoint + * the second selected endpoint within the area of characters + * @param bounds + * the specified bounds of this TextLayout. + * @return a Shape represented the logical selection betweeen the specified + * endpoints. + */ + public Shape getLogicalHighlightShape(int firstEndpoint, int secondEndpoint, Rectangle2D bounds) { + updateMetrics(); + + if (firstEndpoint > secondEndpoint) { + if (secondEndpoint < 0 || firstEndpoint > breaker.getCharCount()) { + // awt.197=Endpoints are out of range + throw new IllegalArgumentException(Messages.getString("awt.197")); //$NON-NLS-1$ + } + return caretManager.getLogicalHighlightShape(secondEndpoint, firstEndpoint, bounds, + this); + } + if (firstEndpoint < 0 || secondEndpoint > breaker.getCharCount()) { + // awt.197=Endpoints are out of range + throw new IllegalArgumentException(Messages.getString("awt.197")); //$NON-NLS-1$ + } + return caretManager.getLogicalHighlightShape(firstEndpoint, secondEndpoint, bounds, this); + } + + /** + * Gets the logical ranges of text which corresponds to a visual selection. + * + * @param hit1 + * the first endpoint of the visual range. + * @param hit2 + * the second endpoint of the visual range. + * @return the logical ranges of text which corresponds to a visual + * selection. + */ + public int[] getLogicalRangesForVisualSelection(TextHitInfo hit1, TextHitInfo hit2) { + return caretManager.getLogicalRangesForVisualSelection(hit1, hit2); + } + + /** + * Gets the TextHitInfo for the next caret to the left (or up at the end of + * the line) of the specified offset. + * + * @param offset + * the offset in this TextLayout. + * @return the TextHitInfo for the next caret to the left (or up at the end + * of the line) of the specified hit, or null if there is no hit. + */ + public TextHitInfo getNextLeftHit(int offset) { + return getNextLeftHit(offset, DEFAULT_CARET_POLICY); + } + + /** + * Gets the TextHitInfo for the next caret to the left (or up at the end of + * the line) of the specified hit. + * + * @param hitInfo + * the initial hit. + * @return the TextHitInfo for the next caret to the left (or up at the end + * of the line) of the specified hit, or null if there is no hit. + */ + public TextHitInfo getNextLeftHit(TextHitInfo hitInfo) { + breaker.createAllSegments(); + return caretManager.getNextLeftHit(hitInfo); + } + + /** + * Gets the TextHitInfo for the next caret to the left (or up at the end of + * the line) of the specified offset, given the specified caret policy. + * + * @param offset + * the offset in this TextLayout. + * @param policy + * the policy to be used for obtaining the strong caret. + * @return the TextHitInfo for the next caret to the left of the specified + * offset, or null if there is no hit. + */ + public TextHitInfo getNextLeftHit(int offset, TextLayout.CaretPolicy policy) { + if (offset < 0 || offset > breaker.getCharCount()) { + // awt.195=Offset is out of bounds + throw new IllegalArgumentException(Messages.getString("awt.195")); //$NON-NLS-1$ + } + + TextHitInfo hit = TextHitInfo.afterOffset(offset); + TextHitInfo strongHit = policy.getStrongCaret(hit, hit.getOtherHit(), this); + TextHitInfo nextLeftHit = getNextLeftHit(strongHit); + + if (nextLeftHit != null) { + return policy.getStrongCaret(getVisualOtherHit(nextLeftHit), nextLeftHit, this); + } + return null; + } + + /** + * Gets the TextHitInfo for the next caret to the right (or down at the end + * of the line) of the specified hit. + * + * @param hitInfo + * the initial hit. + * @return the TextHitInfo for the next caret to the right (or down at the + * end of the line) of the specified hit, or null if there is no + * hit. + */ + public TextHitInfo getNextRightHit(TextHitInfo hitInfo) { + breaker.createAllSegments(); + return caretManager.getNextRightHit(hitInfo); + } + + /** + * Gets the TextHitInfo for the next caret to the right (or down at the end + * of the line) of the specified offset. + * + * @param offset + * the offset in this TextLayout. + * @return the TextHitInfo for the next caret to the right of the specified + * offset, or null if there is no hit. + */ + public TextHitInfo getNextRightHit(int offset) { + return getNextRightHit(offset, DEFAULT_CARET_POLICY); + } + + /** + * Gets the TextHitInfo for the next caret to the right (or down at the end + * of the line) of the specified offset, given the specified caret policy. + * + * @param offset + * the offset in this TextLayout. + * @param policy + * the policy to be used for obtaining the strong caret. + * @return the TextHitInfo for the next caret to the right of the specified + * offset, or null if there is no hit. + */ + public TextHitInfo getNextRightHit(int offset, TextLayout.CaretPolicy policy) { + if (offset < 0 || offset > breaker.getCharCount()) { + // awt.195=Offset is out of bounds + throw new IllegalArgumentException(Messages.getString("awt.195")); //$NON-NLS-1$ + } + + TextHitInfo hit = TextHitInfo.afterOffset(offset); + TextHitInfo strongHit = policy.getStrongCaret(hit, hit.getOtherHit(), this); + TextHitInfo nextRightHit = getNextRightHit(strongHit); + + if (nextRightHit != null) { + return policy.getStrongCaret(getVisualOtherHit(nextRightHit), nextRightHit, this); + } + return null; + } + + /** + * Gets the outline of this TextLayout as a Shape. + * + * @param xform + * the AffineTransform to be used to transform the outline before + * returning it, or null if no transformation is desired. + * @return the outline of this TextLayout as a Shape. + */ + public Shape getOutline(AffineTransform xform) { + breaker.createAllSegments(); + + GeneralPath outline = breaker.getOutline(); + + if (outline != null && xform != null) { + outline.transform(xform); + } + + return outline; + } + + /** + * Gets the visible advance of this TextLayout which is defined as diffence + * between leading (advance) and trailing whitespace. + * + * @return the visible advance of this TextLayout. + */ + public float getVisibleAdvance() { + updateMetrics(); + + // Trailing whitespace _SHOULD_ be reordered (Unicode spec) to + // base direction, so it is also trailing + // in logical representation. We use this fact. + int lastNonWhitespace = breaker.getLastNonWhitespace(); + + if (lastNonWhitespace < 0) { + return 0; + } else if (lastNonWhitespace == getCharacterCount() - 1) { + return getAdvance(); + } else if (justificationWidth >= 0) { // Layout is justified + return justificationWidth; + } else { + breaker.pushSegments(breaker.getACI().getBeginIndex(), lastNonWhitespace + + breaker.getACI().getBeginIndex() + 1); + + breaker.createAllSegments(); + + float visAdvance = tmc.createMetrics().getAdvance(); + + breaker.popSegments(); + return visAdvance; + } + } + + /** + * Gets a Shape which corresponds to the highlighted (selected) area based + * on two hit locations within the text and extends to the bounds. + * + * @param hit1 + * the first text hit location. + * @param hit2 + * the second text hit location. + * @param bounds + * the rectangle that the highlighted area should be extended or + * restricted to. + * @return a Shape which corresponds to the highlighted (selected) area. + */ + public Shape getVisualHighlightShape(TextHitInfo hit1, TextHitInfo hit2, Rectangle2D bounds) { + return caretManager.getVisualHighlightShape(hit1, hit2, bounds, this); + } + + /** + * Gets a Shape which corresponds to the highlighted (selected) area based + * on two hit locations within the text. + * + * @param hit1 + * the first text hit location. + * @param hit2 + * the second text hit location. + * @return a Shape which corresponds to the highlighted (selected) area. + */ + public Shape getVisualHighlightShape(TextHitInfo hit1, TextHitInfo hit2) { + breaker.createAllSegments(); + return caretManager.getVisualHighlightShape(hit1, hit2, breaker.getLogicalBounds(), this); + } + + /** + * Gets the TextHitInfo for a hit on the opposite side of the specified + * hit's caret. + * + * @param hitInfo + * the specified TextHitInfo. + * @return the TextHitInfo for a hit on the opposite side of the specified + * hit's caret. + */ + public TextHitInfo getVisualOtherHit(TextHitInfo hitInfo) { + return caretManager.getVisualOtherHit(hitInfo); + } + + /** + * Justifies the text; this method should be overridden by subclasses. + * + * @param justificationWidth + * the width for justification. + */ + protected void handleJustify(float justificationWidth) { + float justification = breaker.getJustification(); + + if (justification < 0) { + // awt.196=Justification impossible, layout already justified + throw new IllegalStateException(Messages.getString("awt.196")); //$NON-NLS-1$ + } else if (justification == 0) { + return; + } + + float gap = (justificationWidth - getVisibleAdvance()) * justification; + breaker.justify(gap); + this.justificationWidth = justificationWidth; + + // Correct metrics + tmc = new TextMetricsCalculator(breaker); + tmc.correctAdvance(metrics); + } + + /** + * Returns a TextHitInfo object that gives information on which division + * point (between two characters) is corresponds to a hit (such as a mouse + * click) at the specified coordinates. + * + * @param x + * the X coordinate in this TextLayout. + * @param y + * the Y coordinate in this TextLayout. TextHitInfo object + * corresponding to the given coordinates within the text. + * @return the information about the character at the specified position. + */ + public TextHitInfo hitTestChar(float x, float y) { + return hitTestChar(x, y, getBounds()); + } + + /** + * Returns a TextHitInfo object that gives information on which division + * point (between two characters) is corresponds to a hit (such as a mouse + * click) at the specified coordinates within the specified text rectangle. + * + * @param x + * the X coordinate in this TextLayout. + * @param y + * the Y coordinate in this TextLayout. + * @param bounds + * the bounds of the text area. TextHitInfo object corresponding + * to the given coordinates within the text. + * @return the information about the character at the specified position. + */ + public TextHitInfo hitTestChar(float x, float y, Rectangle2D bounds) { + if (x > bounds.getMaxX()) { + return breaker.isLTR() ? TextHitInfo.trailing(breaker.getCharCount() - 1) : TextHitInfo + .leading(0); + } + + if (x < bounds.getMinX()) { + return breaker.isLTR() ? TextHitInfo.leading(0) : TextHitInfo.trailing(breaker + .getCharCount() - 1); + } + + return breaker.hitTest(x, y); + } + + /** + * Returns true if this TextLayout has a "left to right" direction. + * + * @return true if this TextLayout has a "left to right" direction, false if + * this TextLayout has a "right to left" direction. + */ + public boolean isLeftToRight() { + return breaker.isLTR(); + } + + /** + * Returns true if this TextLayout is vertical, false otherwise. + * + * @return true if this TextLayout is vertical, false if horizontal. + */ + public boolean isVertical() { + return false; + } +} diff --git a/app/src/main/java/java/awt/font/TextMeasurer.java b/app/src/main/java/java/awt/font/TextMeasurer.java new file mode 100644 index 000000000..9741f59c4 --- /dev/null +++ b/app/src/main/java/java/awt/font/TextMeasurer.java @@ -0,0 +1,182 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @author Oleg V. Khaschansky + * @version $Revision$ + */ + +package java.awt.font; + +import java.text.AttributedCharacterIterator; + +import org.apache.harmony.awt.gl.font.TextMetricsCalculator; +import org.apache.harmony.awt.gl.font.TextRunBreaker; + +/** + * The TextMeasurer class provides utilities for line break operations. + * + * @since Android 1.0 + */ +public final class TextMeasurer implements Cloneable { + + /** + * The aci. + */ + AttributedCharacterIterator aci; + + /** + * The frc. + */ + FontRenderContext frc; + + /** + * The breaker. + */ + TextRunBreaker breaker = null; + + /** + * The tmc. + */ + TextMetricsCalculator tmc = null; + + /** + * Instantiates a new text measurer from the specified text. + * + * @param text + * the source text. + * @param frc + * the FontRenderContext. + */ + public TextMeasurer(AttributedCharacterIterator text, FontRenderContext frc) { + this.aci = text; + this.frc = frc; + breaker = new TextRunBreaker(aci, this.frc); + tmc = new TextMetricsCalculator(breaker); + } + + /** + * Replaces the current text with the new text, inserting a break character + * at the specified insert position. + * + * @param newParagraph + * the new paragraph text. + * @param insertPos + * the position in the text where the character is inserted. + */ + public void insertChar(AttributedCharacterIterator newParagraph, int insertPos) { + AttributedCharacterIterator oldAci = aci; + aci = newParagraph; + if ((oldAci.getEndIndex() - oldAci.getBeginIndex()) + - (aci.getEndIndex() - aci.getBeginIndex()) != -1) { + breaker = new TextRunBreaker(aci, this.frc); + tmc = new TextMetricsCalculator(breaker); + } else { + breaker.insertChar(newParagraph, insertPos); + } + } + + /** + * Replaces the current text with the new text and deletes a character at + * the specified position. + * + * @param newParagraph + * the paragraph text after deletion. + * @param deletePos + * the position in the text where the character is removed. + */ + public void deleteChar(AttributedCharacterIterator newParagraph, int deletePos) { + AttributedCharacterIterator oldAci = aci; + aci = newParagraph; + if ((oldAci.getEndIndex() - oldAci.getBeginIndex()) + - (aci.getEndIndex() - aci.getBeginIndex()) != 1) { + breaker = new TextRunBreaker(aci, this.frc); + tmc = new TextMetricsCalculator(breaker); + } else { + breaker.deleteChar(newParagraph, deletePos); + } + } + + /** + * Returns a copy of this object. + * + * @return a copy of this object. + */ + @Override + protected Object clone() { + return new TextMeasurer((AttributedCharacterIterator)aci.clone(), frc); + } + + /** + * Returns a TextLayout of the specified character range. + * + * @param start + * the index of the first character. + * @param limit + * the index after the last character. + * @return a TextLayout for the characters beginning at "start" up to "end". + */ + public TextLayout getLayout(int start, int limit) { + breaker.pushSegments(start - aci.getBeginIndex(), limit - aci.getBeginIndex()); + + breaker.createAllSegments(); + TextLayout layout = new TextLayout((TextRunBreaker)breaker.clone()); + + breaker.popSegments(); + return layout; + } + + /** + * Returns the graphical width of a line beginning at "start" parameter and + * including characters up to "end" parameter. "start" and "end" are + * absolute indices, not relative to the "start" of the paragraph. + * + * @param start + * the character index at which to start measuring. + * @param end + * the character index at which to stop measuring. + * @return the graphical width of a line beginning at "start" and including + * characters up to "end". + */ + public float getAdvanceBetween(int start, int end) { + breaker.pushSegments(start - aci.getBeginIndex(), end - aci.getBeginIndex()); + + breaker.createAllSegments(); + float retval = tmc.createMetrics().getAdvance(); + + breaker.popSegments(); + return retval; + } + + /** + * Returns the index of the first character which is not fit on a line + * beginning at start and possible measuring up to maxAdvance in graphical + * width. + * + * @param start + * he character index at which to start measuring. + * @param maxAdvance + * the graphical width in which the line must fit. + * @return the index after the last character that is fit on a line + * beginning at start, which is not longer than maxAdvance in + * graphical width. + */ + public int getLineBreakIndex(int start, float maxAdvance) { + breaker.createAllSegments(); + return breaker.getLineBreakIndex(start - aci.getBeginIndex(), maxAdvance) + + aci.getBeginIndex(); + } +} diff --git a/app/src/main/java/java/awt/font/TransformAttribute.java b/app/src/main/java/java/awt/font/TransformAttribute.java new file mode 100644 index 000000000..ff2caa251 --- /dev/null +++ b/app/src/main/java/java/awt/font/TransformAttribute.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ + +package java.awt.font; + +import java.awt.geom.AffineTransform; +import java.io.Serializable; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The TransformAttribute class is a wrapper for the AffineTransform class in + * order to use it as attribute. + * + * @since Android 1.0 + */ +public final class TransformAttribute implements Serializable { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = 3356247357827709530L; + + // affine transform of this TransformAttribute instance + /** + * The transform. + */ + private AffineTransform fTransform; + + /** + * Instantiates a new TransformAttribute from the specified AffineTransform. + * + * @param transform + * the AffineTransform to be wrapped. + */ + public TransformAttribute(AffineTransform transform) { + if (transform == null) { + // awt.94=transform can not be null + throw new IllegalArgumentException(Messages.getString("awt.94")); //$NON-NLS-1$ + } + if (!transform.isIdentity()) { + this.fTransform = new AffineTransform(transform); + } + } + + /** + * Gets the initial AffineTransform which is wrapped. + * + * @return the initial AffineTransform which is wrapped. + */ + public AffineTransform getTransform() { + if (fTransform != null) { + return new AffineTransform(fTransform); + } + return new AffineTransform(); + } + + /** + * Checks if this transform is an identity transform. + * + * @return true, if this transform is an identity transform, false + * otherwise. + */ + public boolean isIdentity() { + return (fTransform == null); + } + +} diff --git a/app/src/main/java/java/awt/font/package.html b/app/src/main/java/java/awt/font/package.html new file mode 100644 index 000000000..788dcc0a0 --- /dev/null +++ b/app/src/main/java/java/awt/font/package.html @@ -0,0 +1,8 @@ + + +

+ This package contains classes to support the representation of different types of fonts for example TrueType fonts. +

+ @since Android 1.0 + + diff --git a/app/src/main/java/java/awt/geom/FlatteningPathIterator.java b/app/src/main/java/java/awt/geom/FlatteningPathIterator.java index 8208f3963..72b460dad 100644 --- a/app/src/main/java/java/awt/geom/FlatteningPathIterator.java +++ b/app/src/main/java/java/awt/geom/FlatteningPathIterator.java @@ -233,7 +233,7 @@ public class FlatteningPathIterator implements PathIterator { bufIndex -= 6; buf[bufIndex + 0] = px; buf[bufIndex + 1] = py; - System.arraycopy(coords, 0, buf, bufIndex + 2, 4); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(coords, 0, buf, bufIndex + 2, 4); bufSubdiv = 0; } @@ -245,7 +245,7 @@ public class FlatteningPathIterator implements PathIterator { // Realloc buffer if (bufIndex <= 4) { double tmp[] = new double[bufSize + BUFFER_CAPACITY]; - System.arraycopy(buf, bufIndex, tmp, bufIndex + BUFFER_CAPACITY, bufSize + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(buf, bufIndex, tmp, bufIndex + BUFFER_CAPACITY, bufSize - bufIndex); buf = tmp; bufSize += BUFFER_CAPACITY; @@ -275,7 +275,7 @@ public class FlatteningPathIterator implements PathIterator { bufIndex -= 8; buf[bufIndex + 0] = px; buf[bufIndex + 1] = py; - System.arraycopy(coords, 0, buf, bufIndex + 2, 6); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(coords, 0, buf, bufIndex + 2, 6); bufSubdiv = 0; } @@ -287,7 +287,7 @@ public class FlatteningPathIterator implements PathIterator { // Realloc buffer if (bufIndex <= 6) { double tmp[] = new double[bufSize + BUFFER_CAPACITY]; - System.arraycopy(buf, bufIndex, tmp, bufIndex + BUFFER_CAPACITY, bufSize + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(buf, bufIndex, tmp, bufIndex + BUFFER_CAPACITY, bufSize - bufIndex); buf = tmp; bufSize += BUFFER_CAPACITY; diff --git a/app/src/main/java/java/awt/geom/GeneralPath.java b/app/src/main/java/java/awt/geom/GeneralPath.java index 0669bc77b..681324bc6 100644 --- a/app/src/main/java/java/awt/geom/GeneralPath.java +++ b/app/src/main/java/java/awt/geom/GeneralPath.java @@ -181,7 +181,7 @@ public final class GeneralPath implements Shape, Cloneable { } int type = p.types[typeIndex]; int count = GeneralPath.pointShift[type]; - System.arraycopy(p.points, pointIndex, coords, 0, count); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(p.points, pointIndex, coords, 0, count); if (t != null) { t.transform(coords, 0, coords, 0, count / 2); } @@ -290,12 +290,12 @@ public final class GeneralPath implements Shape, Cloneable { } if (typeSize == types.length) { byte tmp[] = new byte[typeSize + BUFFER_CAPACITY]; - System.arraycopy(types, 0, tmp, 0, typeSize); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(types, 0, tmp, 0, typeSize); types = tmp; } if (pointSize + pointCount > points.length) { float tmp[] = new float[pointSize + Math.max(BUFFER_CAPACITY * 2, pointCount)]; - System.arraycopy(points, 0, tmp, 0, pointSize); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(points, 0, tmp, 0, pointSize); points = tmp; } } diff --git a/app/src/main/java/java/awt/im/InputContext.java b/app/src/main/java/java/awt/im/InputContext.java new file mode 100644 index 000000000..cce514842 --- /dev/null +++ b/app/src/main/java/java/awt/im/InputContext.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.im; + +import java.awt.AWTEvent; +//???AWT: import java.awt.Component; +import java.util.Locale; + +import org.apache.harmony.awt.im.InputMethodContext; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public class InputContext { + protected InputContext() { + } + + public static InputContext getInstance() { + return new InputMethodContext(); + } + + public void dispatchEvent(AWTEvent event) { + } + + public void dispose() { + } + + public void endComposition() { + } + + public Object getInputMethodControlObject() { + return null; + } + + public Locale getLocale() { + return null; + } + + public boolean isCompositionEnabled() { + return false; + } + + public void reconvert() { + } + + //???AWT + /* + public void removeNotify(Component client) { + } + */ + + public boolean selectInputMethod(Locale locale) { + return false; + } + + public void setCharacterSubsets(Character.Subset[] subsets) { + } + + public void setCompositionEnabled(boolean enable) { + } +} + diff --git a/app/src/main/java/java/awt/im/InputMethodHighlight.java b/app/src/main/java/java/awt/im/InputMethodHighlight.java new file mode 100644 index 000000000..865d47c80 --- /dev/null +++ b/app/src/main/java/java/awt/im/InputMethodHighlight.java @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Dmitry A. Durnev + * @version $Revision$ + */ +package java.awt.im; + +import java.util.Map; +import java.awt.font.TextAttribute; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public class InputMethodHighlight { + + public static final int RAW_TEXT = 0; + + public static final int CONVERTED_TEXT = 1; + + public static final InputMethodHighlight + UNSELECTED_RAW_TEXT_HIGHLIGHT = new InputMethodHighlight(false, RAW_TEXT); + + public static final InputMethodHighlight + SELECTED_RAW_TEXT_HIGHLIGHT = new InputMethodHighlight(true, RAW_TEXT); + + public static final InputMethodHighlight + UNSELECTED_CONVERTED_TEXT_HIGHLIGHT = + new InputMethodHighlight(false, CONVERTED_TEXT); + + public static final InputMethodHighlight + SELECTED_CONVERTED_TEXT_HIGHLIGHT = + new InputMethodHighlight(true, CONVERTED_TEXT); + + private boolean selected; + private int state; + private int variation; + private Map style; + + public InputMethodHighlight(boolean selected, int state, int variation) { + this(selected, state, variation, null); + } + + public InputMethodHighlight(boolean selected, int state, + int variation, Map style) { + if ((state != RAW_TEXT) && (state != CONVERTED_TEXT)) { + // awt.20B=unknown input method highlight state + throw new IllegalArgumentException(Messages.getString("awt.20B")); //$NON-NLS-1$ + } + this.selected = selected; + this.state = state; + this.variation = variation; + this.style = style; + } + + public InputMethodHighlight(boolean selected, int state) { + this(selected, state, 0, null); + } + + public int getState() { + return state; + } + + public Map getStyle() { + return style; + } + + public int getVariation() { + return variation; + } + + public boolean isSelected() { + return selected; + } +} + diff --git a/app/src/main/java/java/awt/im/InputMethodRequests.java b/app/src/main/java/java/awt/im/InputMethodRequests.java new file mode 100644 index 000000000..b12d397b5 --- /dev/null +++ b/app/src/main/java/java/awt/im/InputMethodRequests.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.im; + +import java.awt.Rectangle; +import java.awt.font.TextHitInfo; +import java.text.AttributedCharacterIterator; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface InputMethodRequests { + + public AttributedCharacterIterator cancelLatestCommittedText(AttributedCharacterIterator.Attribute[] attributes); + + public AttributedCharacterIterator getCommittedText(int beginIndex, int endIndex, AttributedCharacterIterator.Attribute[] attributes); + + public int getCommittedTextLength(); + + public int getInsertPositionOffset(); + + public TextHitInfo getLocationOffset(int x, int y); + + public AttributedCharacterIterator getSelectedText(AttributedCharacterIterator.Attribute[] attributes); + + public Rectangle getTextLocation(TextHitInfo offset); +} + diff --git a/app/src/main/java/java/awt/im/InputSubset.java b/app/src/main/java/java/awt/im/InputSubset.java new file mode 100644 index 000000000..708881eae --- /dev/null +++ b/app/src/main/java/java/awt/im/InputSubset.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Dmitry A. Durnev + * @version $Revision$ + */ +package java.awt.im; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public final class InputSubset extends Character.Subset { + + public static final InputSubset LATIN = new InputSubset("LATIN"); //$NON-NLS-1$ + + public static final InputSubset + LATIN_DIGITS = new InputSubset("LATIN_DIGITS"); //$NON-NLS-1$ + + public static final InputSubset + TRADITIONAL_HANZI = new InputSubset("TRADITIONAL_HANZI"); //$NON-NLS-1$ + + public static final InputSubset + SIMPLIFIED_HANZI = new InputSubset("SIMPLIFIED_HANZI"); //$NON-NLS-1$ + + public static final InputSubset KANJI = new InputSubset("KANJI"); //$NON-NLS-1$ + + public static final InputSubset HANJA = new InputSubset("HANJA"); //$NON-NLS-1$ + + public static final InputSubset + HALFWIDTH_KATAKANA = new InputSubset("HALFWIDTH_KATAKANA"); //$NON-NLS-1$ + + public static final InputSubset + FULLWIDTH_LATIN = new InputSubset("FULLWIDTH_LATIN"); //$NON-NLS-1$ + + public static final InputSubset + FULLWIDTH_DIGITS = new InputSubset("FULLWIDTH_DIGITS"); //$NON-NLS-1$ + + private InputSubset(String name) { + super(name); + } +} + diff --git a/app/src/main/java/java/awt/im/spi/InputMethod.java b/app/src/main/java/java/awt/im/spi/InputMethod.java new file mode 100644 index 000000000..67a88346c --- /dev/null +++ b/app/src/main/java/java/awt/im/spi/InputMethod.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.im.spi; + +import java.awt.AWTEvent; +import java.awt.Rectangle; +import java.util.Locale; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface InputMethod { + + public void activate(); + + public void deactivate(boolean isTemporary); + + public void dispatchEvent(AWTEvent event); + + public void dispose(); + + public void endComposition(); + + public Object getControlObject(); + + public Locale getLocale(); + + public void hideWindows(); + + public boolean isCompositionEnabled(); + + public void notifyClientWindowChange(Rectangle bounds); + + public void reconvert(); + + public void removeNotify(); + + public void setCharacterSubsets(Character.Subset[] subsets); + + public void setCompositionEnabled(boolean enable); + + public void setInputMethodContext(InputMethodContext context); + + public boolean setLocale(Locale locale); +} + diff --git a/app/src/main/java/java/awt/im/spi/InputMethodContext.java b/app/src/main/java/java/awt/im/spi/InputMethodContext.java new file mode 100644 index 000000000..bfc773cf0 --- /dev/null +++ b/app/src/main/java/java/awt/im/spi/InputMethodContext.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.im.spi; + +//???AWT: import java.awt.Window; +import java.awt.font.TextHitInfo; +import java.awt.im.InputMethodRequests; +import java.text.AttributedCharacterIterator; +//???AWT: import javax.swing.JFrame; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface InputMethodContext extends InputMethodRequests { + +// ???AWT: public JFrame createInputMethodJFrame(String title, boolean attachToInputContext); + +// ???AWT: public Window createInputMethodWindow(String title, boolean attachToInputContext); + + public void dispatchInputMethodEvent(int id, AttributedCharacterIterator text, int committedCharacterCount, TextHitInfo caret, TextHitInfo visiblePosition); + + public void enableClientWindowNotification(InputMethod inputMethod, boolean enable); + +} + diff --git a/app/src/main/java/java/awt/im/spi/InputMethodDescriptor.java b/app/src/main/java/java/awt/im/spi/InputMethodDescriptor.java new file mode 100644 index 000000000..c800bc179 --- /dev/null +++ b/app/src/main/java/java/awt/im/spi/InputMethodDescriptor.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.im.spi; + +import java.awt.AWTException; +import java.awt.Image; +import java.util.Locale; + +/** + * This class is not supported in Android 1.0. It is merely provided to maintain + * interface compatibility with desktop Java implementations. + * + * @since Android 1.0 + */ +public interface InputMethodDescriptor { + + public Locale[] getAvailableLocales() throws AWTException; + + public InputMethod createInputMethod() throws Exception; + + public String getInputMethodDisplayName(Locale inputLocale, Locale displayLanguage); + + public Image getInputMethodIcon(Locale inputLocale); + + public boolean hasDynamicLocaleList(); + +} + diff --git a/app/src/main/java/java/awt/image/AffineTransformOp.java b/app/src/main/java/java/awt/image/AffineTransformOp.java new file mode 100644 index 000000000..db25e1aec --- /dev/null +++ b/app/src/main/java/java/awt/image/AffineTransformOp.java @@ -0,0 +1,618 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky, Denis M. Kishenko + * @version $Revision$ + */ + +package java.awt.image; + +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.geom.Point2D; +import java.awt.geom.NoninvertibleTransformException; +import java.awt.*; +import java.util.Arrays; + +import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The AffineTransform class translates coordinates from 2D coordinates in the + * source image or Raster to 2D coordinates in the destination image or Raster + * using affine transformation. The number of bands in the source Raster should + * equal to the number of bands in the destination Raster. + * + * @since Android 1.0 + */ +public class AffineTransformOp implements BufferedImageOp, RasterOp { + + /** + * The Constant TYPE_NEAREST_NEIGHBOR indicates nearest-neighbor + * interpolation type. + */ + public static final int TYPE_NEAREST_NEIGHBOR = 1; + + /** + * The Constant TYPE_BILINEAR indicates bilinear interpolation type. + */ + public static final int TYPE_BILINEAR = 2; + + /** + * The Constant TYPE_BICUBIC indicates bi-cubic interpolation type. + */ + public static final int TYPE_BICUBIC = 3; + + /** + * The i type. + */ + private int iType; // interpolation type + + /** + * The at. + */ + private AffineTransform at; + + /** + * The hints. + */ + private RenderingHints hints; + + static { + // TODO - uncomment + // System.loadLibrary("imageops"); + } + + /** + * Instantiates a new AffineTransformOp with the specified AffineTransform + * and RenderingHints object which defines the interpolation type. + * + * @param xform + * the AffineTransform. + * @param hints + * the RenderingHints object which defines the interpolation + * type. + */ + public AffineTransformOp(AffineTransform xform, RenderingHints hints) { + this(xform, TYPE_NEAREST_NEIGHBOR); + this.hints = hints; + + if (hints != null) { + Object hint = hints.get(RenderingHints.KEY_INTERPOLATION); + if (hint != null) { + // Nearest neighbor is default + if (hint == RenderingHints.VALUE_INTERPOLATION_BILINEAR) { + this.iType = TYPE_BILINEAR; + } else if (hint == RenderingHints.VALUE_INTERPOLATION_BICUBIC) { + this.iType = TYPE_BICUBIC; + } + } else { + hint = hints.get(RenderingHints.KEY_RENDERING); + // Determine from rendering quality + if (hint == RenderingHints.VALUE_RENDER_QUALITY) { + this.iType = TYPE_BILINEAR; + // For speed use nearest neighbor + } + } + } + } + + /** + * Instantiates a new AffineTransformOp with the specified AffineTransform + * and a specified interpolation type from the list of predefined + * interpolation types. + * + * @param xform + * the AffineTransform. + * @param interp + * the one of predefined interpolation types: + * TYPE_NEAREST_NEIGHBOR, TYPE_BILINEAR, or TYPE_BICUBIC. + */ + public AffineTransformOp(AffineTransform xform, int interp) { + if (Math.abs(xform.getDeterminant()) <= Double.MIN_VALUE) { + // awt.24F=Unable to invert transform {0} + throw new ImagingOpException(Messages.getString("awt.24F", xform)); //$NON-NLS-1$ + } + + this.at = (AffineTransform)xform.clone(); + + if (interp != TYPE_NEAREST_NEIGHBOR && interp != TYPE_BILINEAR && interp != TYPE_BICUBIC) { + // awt.250=Unknown interpolation type: {0} + throw new IllegalArgumentException(Messages.getString("awt.250", interp)); //$NON-NLS-1$ + } + + this.iType = interp; + } + + /** + * Gets the interpolation type. + * + * @return the interpolation type. + */ + public final int getInterpolationType() { + return iType; + } + + public final RenderingHints getRenderingHints() { + if (hints == null) { + Object value = null; + + switch (iType) { + case TYPE_NEAREST_NEIGHBOR: + value = RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR; + break; + case TYPE_BILINEAR: + value = RenderingHints.VALUE_INTERPOLATION_BILINEAR; + break; + case TYPE_BICUBIC: + value = RenderingHints.VALUE_INTERPOLATION_BICUBIC; + break; + default: + value = RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR; + } + + hints = new RenderingHints(RenderingHints.KEY_INTERPOLATION, value); + } + + return hints; + } + + /** + * Gets the affine transform associated with this AffineTransformOp. + * + * @return the AffineTransform. + */ + public final AffineTransform getTransform() { + return (AffineTransform)at.clone(); + } + + public final Point2D getPoint2D(Point2D srcPt, Point2D dstPt) { + return at.transform(srcPt, dstPt); + } + + public final Rectangle2D getBounds2D(BufferedImage src) { + return getBounds2D(src.getRaster()); + } + + public final Rectangle2D getBounds2D(Raster src) { + // We position source raster to (0,0) even if it is translated child + // raster. + // This means that we need only width and height of the src + int width = src.getWidth(); + int height = src.getHeight(); + + float[] corners = { + 0, 0, width, 0, width, height, 0, height + }; + + at.transform(corners, 0, corners, 0, 4); + + Rectangle2D.Float bounds = new Rectangle2D.Float(corners[0], corners[1], 0, 0); + bounds.add(corners[2], corners[3]); + bounds.add(corners[4], corners[5]); + bounds.add(corners[6], corners[7]); + + return bounds; + } + + public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel destCM) { + Rectangle2D newBounds = getBounds2D(src); + + // Destination image should include (0,0) + positive part + // of the area bounded by newBounds (in source coordinate system). + double dstWidth = newBounds.getX() + newBounds.getWidth(); + double dstHeight = newBounds.getY() + newBounds.getHeight(); + + if (dstWidth <= 0 || dstHeight <= 0) { + // awt.251=Transformed width ({0}) and height ({1}) should be + // greater than 0 + throw new RasterFormatException(Messages.getString("awt.251", dstWidth, dstHeight)); //$NON-NLS-1$ + } + + if (destCM != null) { + return new BufferedImage(destCM, destCM.createCompatibleWritableRaster((int)dstWidth, + (int)dstHeight), destCM.isAlphaPremultiplied(), null); + } + + ColorModel cm = src.getColorModel(); + + // Interpolation other than NN doesn't make any sense for index color + if (iType != TYPE_NEAREST_NEIGHBOR && cm instanceof IndexColorModel) { + return new BufferedImage((int)dstWidth, (int)dstHeight, BufferedImage.TYPE_INT_ARGB); + } + + // OK, we can get source color model + return new BufferedImage(cm, src.getRaster().createCompatibleWritableRaster((int)dstWidth, + (int)dstHeight), cm.isAlphaPremultiplied(), null); + } + + public WritableRaster createCompatibleDestRaster(Raster src) { + // Here approach is other then in createCompatibleDestImage - + // destination should include only + // transformed image, but not (0,0) in source coordinate system + + Rectangle2D newBounds = getBounds2D(src); + return src.createCompatibleWritableRaster((int)newBounds.getX(), (int)newBounds.getY(), + (int)newBounds.getWidth(), (int)newBounds.getHeight()); + } + + public final BufferedImage filter(BufferedImage src, BufferedImage dst) { + if (src == dst) { + // awt.252=Source can't be same as the destination + throw new IllegalArgumentException(Messages.getString("awt.252")); //$NON-NLS-1$ + } + + ColorModel srcCM = src.getColorModel(); + BufferedImage finalDst = null; + + if (srcCM instanceof IndexColorModel + && (iType != TYPE_NEAREST_NEIGHBOR || srcCM.getPixelSize() % 8 != 0)) { + src = ((IndexColorModel)srcCM).convertToIntDiscrete(src.getRaster(), true); + srcCM = src.getColorModel(); + } + + if (dst == null) { + dst = createCompatibleDestImage(src, srcCM); + } else { + if (!srcCM.equals(dst.getColorModel())) { + // Treat BufferedImage.TYPE_INT_RGB and + // BufferedImage.TYPE_INT_ARGB as same + if (!((src.getType() == BufferedImage.TYPE_INT_RGB || src.getType() == BufferedImage.TYPE_INT_ARGB) && (dst + .getType() == BufferedImage.TYPE_INT_RGB || dst.getType() == BufferedImage.TYPE_INT_ARGB))) { + finalDst = dst; + dst = createCompatibleDestImage(src, srcCM); + } + } + } + + // Skip alpha channel for TYPE_INT_RGB images + if (slowFilter(src.getRaster(), dst.getRaster()) != 0) { + // awt.21F=Unable to transform source + throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$ + // TODO - uncomment + // if (ippFilter(src.getRaster(), dst.getRaster(), src.getType()) != + // 0) + // throw new ImagingOpException ("Unable to transform source"); + } + + if (finalDst != null) { + Graphics2D g = finalDst.createGraphics(); + g.setComposite(AlphaComposite.Src); + g.drawImage(dst, 0, 0, null); + } else { + finalDst = dst; + } + + return finalDst; + } + + public final WritableRaster filter(Raster src, WritableRaster dst) { + if (src == dst) { + // awt.252=Source can't be same as the destination + throw new IllegalArgumentException(Messages.getString("awt.252")); //$NON-NLS-1$ + } + + if (dst == null) { + dst = createCompatibleDestRaster(src); + } else if (src.getNumBands() != dst.getNumBands()) { + // awt.253=Different number of bands in source and destination + throw new IllegalArgumentException(Messages.getString("awt.253")); //$NON-NLS-1$ + } + + if (slowFilter(src, dst) != 0) { + // awt.21F=Unable to transform source + throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$ + // TODO - uncomment + // if (ippFilter(src, dst, BufferedImage.TYPE_CUSTOM) != 0) + // throw new ImagingOpException("Unable to transform source"); + } + + return dst; + } + + // TODO remove when method is used + /** + * Ipp filter. + * + * @param src + * the src. + * @param dst + * the dst. + * @param imageType + * the image type. + * @return the int. + */ + @SuppressWarnings("unused") + private int ippFilter(Raster src, WritableRaster dst, int imageType) { + int srcStride, dstStride; + boolean skipChannel = false; + int channels; + int offsets[] = null; + + switch (imageType) { + case BufferedImage.TYPE_INT_RGB: + case BufferedImage.TYPE_INT_BGR: { + channels = 4; + srcStride = src.getWidth() * 4; + dstStride = dst.getWidth() * 4; + skipChannel = true; + break; + } + + case BufferedImage.TYPE_INT_ARGB: + case BufferedImage.TYPE_INT_ARGB_PRE: + case BufferedImage.TYPE_4BYTE_ABGR: + case BufferedImage.TYPE_4BYTE_ABGR_PRE: { + channels = 4; + srcStride = src.getWidth() * 4; + dstStride = dst.getWidth() * 4; + break; + } + + case BufferedImage.TYPE_BYTE_GRAY: + case BufferedImage.TYPE_BYTE_INDEXED: { + channels = 1; + srcStride = src.getWidth(); + dstStride = dst.getWidth(); + break; + } + + case BufferedImage.TYPE_3BYTE_BGR: { + channels = 3; + srcStride = src.getWidth() * 3; + dstStride = dst.getWidth() * 3; + break; + } + + case BufferedImage.TYPE_USHORT_GRAY: // TODO - could be done in + // native code? + case BufferedImage.TYPE_USHORT_565_RGB: + case BufferedImage.TYPE_USHORT_555_RGB: + case BufferedImage.TYPE_BYTE_BINARY: { + return slowFilter(src, dst); + } + + default: { + SampleModel srcSM = src.getSampleModel(); + SampleModel dstSM = dst.getSampleModel(); + + if (srcSM instanceof PixelInterleavedSampleModel + && dstSM instanceof PixelInterleavedSampleModel) { + // Check PixelInterleavedSampleModel + if (srcSM.getDataType() != DataBuffer.TYPE_BYTE + || dstSM.getDataType() != DataBuffer.TYPE_BYTE) { + return slowFilter(src, dst); + } + + channels = srcSM.getNumBands(); // Have IPP functions for 1, + // 3 and 4 channels + if (channels != 1 && channels != 3 && channels != 4) { + return slowFilter(src, dst); + } + + int dataTypeSize = DataBuffer.getDataTypeSize(srcSM.getDataType()) / 8; + + srcStride = ((ComponentSampleModel)srcSM).getScanlineStride() * dataTypeSize; + dstStride = ((ComponentSampleModel)dstSM).getScanlineStride() * dataTypeSize; + } else if (srcSM instanceof SinglePixelPackedSampleModel + && dstSM instanceof SinglePixelPackedSampleModel) { + // Check SinglePixelPackedSampleModel + SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel)srcSM; + SinglePixelPackedSampleModel sppsm2 = (SinglePixelPackedSampleModel)dstSM; + + // No IPP function for this type + if (sppsm1.getDataType() == DataBuffer.TYPE_USHORT) { + return slowFilter(src, dst); + } + + channels = sppsm1.getNumBands(); + // Have IPP functions for 1, 3 and 4 channels + if (channels != 1 && channels != 3 && channels != 4) { + return slowFilter(src, dst); + } + + // Check compatibility of sample models + if (sppsm1.getDataType() != sppsm2.getDataType() + || !Arrays.equals(sppsm1.getBitOffsets(), sppsm2.getBitOffsets()) + || !Arrays.equals(sppsm1.getBitMasks(), sppsm2.getBitMasks())) { + return slowFilter(src, dst); + } + + for (int i = 0; i < channels; i++) { + if (sppsm1.getSampleSize(i) != 8) { + return slowFilter(src, dst); + } + } + + if (channels == 3) { + channels = 4; + } + + int dataTypeSize = DataBuffer.getDataTypeSize(sppsm1.getDataType()) / 8; + + srcStride = sppsm1.getScanlineStride() * dataTypeSize; + dstStride = sppsm2.getScanlineStride() * dataTypeSize; + } else { + return slowFilter(src, dst); + } + + // Fill offsets if there's a child raster + if (src.getParent() != null || dst.getParent() != null) { + if (src.getSampleModelTranslateX() != 0 || src.getSampleModelTranslateY() != 0 + || dst.getSampleModelTranslateX() != 0 + || dst.getSampleModelTranslateY() != 0) { + offsets = new int[4]; + offsets[0] = -src.getSampleModelTranslateX() + src.getMinX(); + offsets[1] = -src.getSampleModelTranslateY() + src.getMinY(); + offsets[2] = -dst.getSampleModelTranslateX() + dst.getMinX(); + offsets[3] = -dst.getSampleModelTranslateY() + dst.getMinY(); + } + } + } + } + + double m00 = at.getScaleX(); + double m01 = at.getShearX(); + double m02 = at.getTranslateX(); + double m10 = at.getShearY(); + double m11 = at.getScaleY(); + double m12 = at.getTranslateY(); + + Object srcData, dstData; + AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance(); + try { + srcData = dbAccess.getData(src.getDataBuffer()); + dstData = dbAccess.getData(dst.getDataBuffer()); + } catch (IllegalArgumentException e) { + return -1; // Unknown data buffer type + } + + return ippAffineTransform(m00, m01, m02, m10, m11, m12, srcData, src.getWidth(), src + .getHeight(), srcStride, dstData, dst.getWidth(), dst.getHeight(), dstStride, + iType, channels, skipChannel, offsets); + } + + /** + * Slow filter. + * + * @param src + * the src. + * @param dst + * the dst. + * @return the int. + */ + private int slowFilter(Raster src, WritableRaster dst) { + // TODO: make correct interpolation + // TODO: what if there are different data types? + + Rectangle srcBounds = src.getBounds(); + Rectangle dstBounds = dst.getBounds(); + Rectangle normDstBounds = new Rectangle(0, 0, dstBounds.width, dstBounds.height); + Rectangle bounds = getBounds2D(src).getBounds().intersection(normDstBounds); + + AffineTransform inv = null; + try { + inv = at.createInverse(); + } catch (NoninvertibleTransformException e) { + return -1; + } + + double[] m = new double[6]; + inv.getMatrix(m); + + int minSrcX = srcBounds.x; + int minSrcY = srcBounds.y; + int maxSrcX = srcBounds.x + srcBounds.width; + int maxSrcY = srcBounds.y + srcBounds.height; + + int minX = bounds.x + dstBounds.x; + int minY = bounds.y + dstBounds.y; + int maxX = minX + bounds.width; + int maxY = minY + bounds.height; + + int hx = (int)(m[0] * 256); + int hy = (int)(m[1] * 256); + int vx = (int)(m[2] * 256); + int vy = (int)(m[3] * 256); + int sx = (int)(m[4] * 256) + hx * bounds.x + vx * bounds.y + (srcBounds.x) * 256; + int sy = (int)(m[5] * 256) + hy * bounds.x + vy * bounds.y + (srcBounds.y) * 256; + + vx -= hx * bounds.width; + vy -= hy * bounds.width; + + if (src.getTransferType() == dst.getTransferType()) { + for (int y = minY; y < maxY; y++) { + for (int x = minX; x < maxX; x++) { + int px = sx >> 8; + int py = sy >> 8; + if (px >= minSrcX && py >= minSrcY && px < maxSrcX && py < maxSrcY) { + Object val = src.getDataElements(px, py, null); + dst.setDataElements(x, y, val); + } + sx += hx; + sy += hy; + } + sx += vx; + sy += vy; + } + } else { + float pixel[] = null; + for (int y = minY; y < maxY; y++) { + for (int x = minX; x < maxX; x++) { + int px = sx >> 8; + int py = sy >> 8; + if (px >= minSrcX && py >= minSrcY && px < maxSrcX && py < maxSrcY) { + pixel = src.getPixel(px, py, pixel); + dst.setPixel(x, y, pixel); + } + sx += hx; + sy += hy; + } + sx += vx; + sy += vy; + } + } + + return 0; + } + + /** + * Ipp affine transform. + * + * @param m00 + * the m00. + * @param m01 + * the m01. + * @param m02 + * the m02. + * @param m10 + * the m10. + * @param m11 + * the m11. + * @param m12 + * the m12. + * @param src + * the src. + * @param srcWidth + * the src width. + * @param srcHeight + * the src height. + * @param srcStride + * the src stride. + * @param dst + * the dst. + * @param dstWidth + * the dst width. + * @param dstHeight + * the dst height. + * @param dstStride + * the dst stride. + * @param iType + * the i type. + * @param channels + * the channels. + * @param skipChannel + * the skip channel. + * @param offsets + * the offsets. + * @return the int. + */ + private native int ippAffineTransform(double m00, double m01, double m02, double m10, + double m11, double m12, Object src, int srcWidth, int srcHeight, int srcStride, + Object dst, int dstWidth, int dstHeight, int dstStride, int iType, int channels, + boolean skipChannel, int offsets[]); +} \ No newline at end of file diff --git a/app/src/main/java/java/awt/image/AreaAveragingScaleFilter.java b/app/src/main/java/java/awt/image/AreaAveragingScaleFilter.java new file mode 100644 index 000000000..7fb138e7f --- /dev/null +++ b/app/src/main/java/java/awt/image/AreaAveragingScaleFilter.java @@ -0,0 +1,288 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.util.Arrays; + +/** + * The AreaAveragingScaleFilter class scales the source image using area + * averaging algorithm. This algorithm provides a source image with a new image + * containing the resampled image. + * + * @since Android 1.0 + */ +public class AreaAveragingScaleFilter extends ReplicateScaleFilter { + + /** + * The Constant rgbCM. + */ + private static final ColorModel rgbCM = ColorModel.getRGBdefault(); + + /** + * The Constant averagingFlags. + */ + private static final int averagingFlags = (ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES); + + /** + * The reset. + */ + private boolean reset = true; // Flag for used superclass filter + + /** + * The inited. + */ + private boolean inited = false; // All data inited + + /** + * The sum_r. + */ + private int sum_r[]; // Array for average Red samples + + /** + * The sum_g. + */ + private int sum_g[]; // Array for average Green samples + + /** + * The sum_b. + */ + private int sum_b[]; // Array for average Blue samples + + /** + * The sum_a. + */ + private int sum_a[]; // Array for average Alpha samples + + /** + * The buff. + */ + private int buff[]; // Stride buffer + + /** + * The avg factor. + */ + private int avgFactor; // Global averaging factor + + /** + * The cached dy. + */ + private int cachedDY; // Cached number of the destination scanline + + /** + * The cached dv rest. + */ + private int cachedDVRest; // Cached value of rest src scanlines for sum + + // pixel samples + // Because data if transferring by whole scanlines + // we are caching only Y coordinate values + + /** + * Instantiates a new AreaAveragingScaleFilter object which scales a source + * image with the specified width and height. + * + * @param width + * the scaled width of the image. + * @param height + * the scaled height of the image. + */ + public AreaAveragingScaleFilter(int width, int height) { + super(width, height); + } + + @Override + public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off, + int scansize) { + if (reset) { + super.setPixels(x, y, w, h, model, pixels, off, scansize); + } else { + setFilteredPixels(x, y, w, h, model, pixels, off, scansize); + } + } + + @Override + public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, + int scansize) { + if (reset) { + super.setPixels(x, y, w, h, model, pixels, off, scansize); + } else { + setFilteredPixels(x, y, w, h, model, pixels, off, scansize); + } + } + + @Override + public void setHints(int hints) { + super.setHints(hints); + reset = ((hints & averagingFlags) != averagingFlags); + } + + /** + * This method implements the Area Averaging Scale filter. The description + * of algorithm is presented in Java API Specification. Arrays sum_r, sum_g, + * sum_b, sum_a have length equals width of destination image. In each + * array's element is accumulating pixel's component values, proportional to + * the area which source pixels will occupy in destination image. Then that + * values will divide by Global averaging factor (area of the destination + * image) for receiving average values of destination pixels. + * + * @param x + * the source pixels X coordinate. + * @param y + * the source pixels Y coordinate. + * @param w + * the width of the area of the source pixels. + * @param h + * the height of the area of the source pixels. + * @param model + * the color model of the source pixels. + * @param pixels + * the array of source pixels. + * @param off + * the offset into the source pixels array. + * @param scansize + * the length of scanline in the pixels array. + */ + private void setFilteredPixels(int x, int y, int w, int h, ColorModel model, Object pixels, + int off, int scansize) { + if (!inited) { + initialize(); + } + + int srcX, srcY, dx, dy; + int svRest, dvRest, shRest, dhRest, vDif, hDif; + + if (y == 0) { + dy = 0; + dvRest = srcHeight; + } else { + dy = cachedDY; + dvRest = cachedDVRest; + } + + srcY = y; + svRest = destHeight; + + int srcOff = off; + while (srcY < y + h) { + if (svRest < dvRest) { + vDif = svRest; + } else { + vDif = dvRest; + } + + srcX = 0; + dx = 0; + shRest = destWidth; + dhRest = srcWidth; + while (srcX < w) { + if (shRest < dhRest) { + hDif = shRest; + } else { + hDif = dhRest; + } + int avg = hDif * vDif; // calculation of contribution factor + + int rgb, pix; + if (pixels instanceof int[]) { + pix = ((int[])pixels)[srcOff + srcX]; + } else { + pix = ((byte[])pixels)[srcOff + srcX] & 0xff; + } + + rgb = model.getRGB(pix); + int a = rgb >>> 24; + int r = (rgb >> 16) & 0xff; + int g = (rgb >> 8) & 0xff; + int b = rgb & 0xff; + + // accumulating pixel's component values + sum_a[dx] += a * avg; + sum_r[dx] += r * avg; + sum_g[dx] += g * avg; + sum_b[dx] += b * avg; + + shRest -= hDif; + dhRest -= hDif; + + if (shRest == 0) { + srcX++; + shRest = destWidth; + } + + if (dhRest == 0) { + dx++; + dhRest = srcWidth; + } + } + + svRest -= vDif; + dvRest -= vDif; + + if (svRest == 0) { + svRest = destHeight; + srcY++; + srcOff += scansize; + } + + if (dvRest == 0) { + // averaging destination pixel's values + for (int i = 0; i < destWidth; i++) { + int a = (sum_a[i] / avgFactor) & 0xff; + int r = (sum_r[i] / avgFactor) & 0xff; + int g = (sum_g[i] / avgFactor) & 0xff; + int b = (sum_b[i] / avgFactor) & 0xff; + int frgb = (a << 24) | (r << 16) | (g << 8) | b; + buff[i] = frgb; + } + consumer.setPixels(0, dy, destWidth, 1, rgbCM, buff, 0, destWidth); + dy++; + dvRest = srcHeight; + Arrays.fill(sum_a, 0); + Arrays.fill(sum_r, 0); + Arrays.fill(sum_g, 0); + Arrays.fill(sum_b, 0); + } + + } + + cachedDY = dy; + cachedDVRest = dvRest; + + } + + /** + * Initialization of the auxiliary data. + */ + private void initialize() { + + sum_a = new int[destWidth]; + sum_r = new int[destWidth]; + sum_g = new int[destWidth]; + sum_b = new int[destWidth]; + + buff = new int[destWidth]; + outpixbuf = buff; + avgFactor = srcWidth * srcHeight; + + inited = true; + } +} diff --git a/app/src/main/java/java/awt/image/AwtImageBackdoorAccessorImpl.java b/app/src/main/java/java/awt/image/AwtImageBackdoorAccessorImpl.java new file mode 100644 index 000000000..6dffee88f --- /dev/null +++ b/app/src/main/java/java/awt/image/AwtImageBackdoorAccessorImpl.java @@ -0,0 +1,156 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + * Created on 23.11.2005 + * + */ + +package java.awt.image; + +import java.awt.Image; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; +import java.awt.image.DataBufferDouble; +import java.awt.image.DataBufferFloat; +import java.awt.image.DataBufferInt; +import java.awt.image.DataBufferShort; +import java.awt.image.DataBufferUShort; + +import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor; +import org.apache.harmony.awt.gl.GLVolatileImage; +import org.apache.harmony.awt.gl.Surface; +import org.apache.harmony.awt.gl.image.DataBufferListener; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * This class not part of public API. It useful for receiving package private + * data from other packages. + * + * @since Android 1.0 + */ +class AwtImageBackdoorAccessorImpl extends AwtImageBackdoorAccessor { + + static void init() { + inst = new AwtImageBackdoorAccessorImpl(); + } + + @Override + public Surface getImageSurface(Image image) { + if (image instanceof BufferedImage) { + return ((BufferedImage)image).getImageSurface(); + } else if (image instanceof GLVolatileImage) { + return ((GLVolatileImage)image).getImageSurface(); + } + return null; + } + + @Override + public boolean isGrayPallete(IndexColorModel icm) { + return icm.isGrayPallete(); + } + + @Override + public Object getData(DataBuffer db) { + if (db instanceof DataBufferByte) { + return ((DataBufferByte)db).getData(); + } else if (db instanceof DataBufferUShort) { + return ((DataBufferUShort)db).getData(); + } else if (db instanceof DataBufferShort) { + return ((DataBufferShort)db).getData(); + } else if (db instanceof DataBufferInt) { + return ((DataBufferInt)db).getData(); + } else if (db instanceof DataBufferFloat) { + return ((DataBufferFloat)db).getData(); + } else if (db instanceof DataBufferDouble) { + return ((DataBufferDouble)db).getData(); + } else { + // awt.235=Wrong Data Buffer type : {0} + throw new IllegalArgumentException(Messages.getString("awt.235", //$NON-NLS-1$ + db.getClass())); + } + } + + @Override + public int[] getDataInt(DataBuffer db) { + if (db instanceof DataBufferInt) { + return ((DataBufferInt)db).getData(); + } + return null; + } + + @Override + public byte[] getDataByte(DataBuffer db) { + if (db instanceof DataBufferByte) { + return ((DataBufferByte)db).getData(); + } + return null; + } + + @Override + public short[] getDataShort(DataBuffer db) { + if (db instanceof DataBufferShort) { + return ((DataBufferShort)db).getData(); + } + return null; + } + + @Override + public short[] getDataUShort(DataBuffer db) { + if (db instanceof DataBufferUShort) { + return ((DataBufferUShort)db).getData(); + } + return null; + } + + @Override + public double[] getDataDouble(DataBuffer db) { + if (db instanceof DataBufferDouble) { + return ((DataBufferDouble)db).getData(); + } + return null; + } + + @Override + public float[] getDataFloat(DataBuffer db) { + if (db instanceof DataBufferFloat) { + return ((DataBufferFloat)db).getData(); + } + return null; + } + + @Override + public void addDataBufferListener(DataBuffer db, DataBufferListener listener) { + db.addDataBufferListener(listener); + } + + @Override + public void removeDataBufferListener(DataBuffer db) { + db.removeDataBufferListener(); + } + + @Override + public void validate(DataBuffer db) { + db.validate(); + } + + @Override + public void releaseData(DataBuffer db) { + db.releaseData(); + } +} diff --git a/app/src/main/java/java/awt/image/BandCombineOp.java b/app/src/main/java/java/awt/image/BandCombineOp.java new file mode 100644 index 000000000..1c4a39e39 --- /dev/null +++ b/app/src/main/java/java/awt/image/BandCombineOp.java @@ -0,0 +1,658 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + * + * @date: Sep 20, 2005 + */ + +package java.awt.image; + +import java.awt.*; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.util.Arrays; + +import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The BandCombineOp class translates coordinates from coordinates in the source + * Raster to coordinates in the destination Raster by an arbitrary linear + * combination of the bands in a source Raster, using a specified matrix. The + * number of bands in the matrix should equal to the number of bands in the + * source Raster plus 1. + * + * @since Android 1.0 + */ +public class BandCombineOp implements RasterOp { + + /** + * The Constant offsets3c. + */ + static final int offsets3c[] = { + 16, 8, 0 + }; + + /** + * The Constant offsets4ac. + */ + static final int offsets4ac[] = { + 16, 8, 0, 24 + }; + + /** + * The Constant masks3c. + */ + static final int masks3c[] = { + 0xFF0000, 0xFF00, 0xFF + }; + + /** + * The Constant masks4ac. + */ + static final int masks4ac[] = { + 0xFF0000, 0xFF00, 0xFF, 0xFF000000 + }; + + /** + * The Constant piOffsets. + */ + private static final int piOffsets[] = { + 0, 1, 2 + }; + + /** + * The Constant piInvOffsets. + */ + private static final int piInvOffsets[] = { + 2, 1, 0 + }; + + /** + * The Constant TYPE_BYTE3C. + */ + private static final int TYPE_BYTE3C = 0; + + /** + * The Constant TYPE_BYTE4AC. + */ + private static final int TYPE_BYTE4AC = 1; + + /** + * The Constant TYPE_USHORT3C. + */ + private static final int TYPE_USHORT3C = 2; + + /** + * The Constant TYPE_SHORT3C. + */ + private static final int TYPE_SHORT3C = 3; + + /** + * The mx width. + */ + private int mxWidth; + + /** + * The mx height. + */ + private int mxHeight; + + /** + * The matrix. + */ + private float matrix[][]; + + /** + * The r hints. + */ + private RenderingHints rHints; + + static { + // XXX - todo + // System.loadLibrary("imageops"); + } + + /** + * Instantiates a new BandCombineOp object with the specified matrix. + * + * @param matrix + * the specified matrix for band combining. + * @param hints + * the RenderingHints. + */ + public BandCombineOp(float matrix[][], RenderingHints hints) { + this.mxHeight = matrix.length; + this.mxWidth = matrix[0].length; + this.matrix = new float[mxHeight][mxWidth]; + + for (int i = 0; i < mxHeight; i++) { + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(matrix[i], 0, this.matrix[i], 0, mxWidth); + } + + this.rHints = hints; + } + + public final RenderingHints getRenderingHints() { + return this.rHints; + } + + /** + * Gets the matrix associated with this BandCombineOp object. + * + * @return the matrix associated with this BandCombineOp object. + */ + public final float[][] getMatrix() { + float res[][] = new float[mxHeight][mxWidth]; + + for (int i = 0; i < mxHeight; i++) { + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(matrix[i], 0, res[i], 0, mxWidth); + } + + return res; + } + + public final Point2D getPoint2D(Point2D srcPoint, Point2D dstPoint) { + if (dstPoint == null) { + dstPoint = new Point2D.Float(); + } + + dstPoint.setLocation(srcPoint); + return dstPoint; + } + + public final Rectangle2D getBounds2D(Raster src) { + return src.getBounds(); + } + + public WritableRaster createCompatibleDestRaster(Raster src) { + int numBands = src.getNumBands(); + if (mxWidth != numBands && mxWidth != (numBands + 1) || numBands != mxHeight) { + // awt.254=Number of bands in the source raster ({0}) is + // incompatible with the matrix [{1}x{2}] + throw new IllegalArgumentException(Messages.getString("awt.254", //$NON-NLS-1$ + new Object[] { + numBands, mxWidth, mxHeight + })); + } + + return src.createCompatibleWritableRaster(src.getWidth(), src.getHeight()); + } + + public WritableRaster filter(Raster src, WritableRaster dst) { + int numBands = src.getNumBands(); + + if (mxWidth != numBands && mxWidth != (numBands + 1)) { + // awt.254=Number of bands in the source raster ({0}) is + // incompatible with the matrix [{1}x{2}] + throw new IllegalArgumentException(Messages.getString("awt.254", //$NON-NLS-1$ + new Object[] { + numBands, mxWidth, mxHeight + })); + } + + if (dst == null) { + dst = createCompatibleDestRaster(src); + } else if (dst.getNumBands() != mxHeight) { + // awt.255=Number of bands in the destination raster ({0}) is + // incompatible with the matrix [{1}x{2}] + throw new IllegalArgumentException(Messages.getString("awt.255", //$NON-NLS-1$ + new Object[] { + dst.getNumBands(), mxWidth, mxHeight + })); + } + + // XXX - todo + // if (ippFilter(src, dst) != 0) + if (verySlowFilter(src, dst) != 0) { + // awt.21F=Unable to transform source + throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$ + } + + return dst; + } + + /** + * The Class SampleModelInfo. + */ + private static final class SampleModelInfo { + + /** + * The channels. + */ + int channels; + + /** + * The channels order. + */ + int channelsOrder[]; + + /** + * The stride. + */ + int stride; + } + + /** + * Check sample model. + * + * @param sm + * the sm. + * @return the sample model info. + */ + private final SampleModelInfo checkSampleModel(SampleModel sm) { + SampleModelInfo ret = new SampleModelInfo(); + + if (sm instanceof PixelInterleavedSampleModel) { + // Check PixelInterleavedSampleModel + if (sm.getDataType() != DataBuffer.TYPE_BYTE) { + return null; + } + + ret.channels = sm.getNumBands(); + ret.stride = ((ComponentSampleModel)sm).getScanlineStride(); + ret.channelsOrder = ((ComponentSampleModel)sm).getBandOffsets(); + + } else if (sm instanceof SinglePixelPackedSampleModel) { + // Check SinglePixelPackedSampleModel + SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel)sm; + + ret.channels = sppsm1.getNumBands(); + if (sppsm1.getDataType() != DataBuffer.TYPE_INT) { + return null; + } + + // Check sample models + for (int i = 0; i < ret.channels; i++) { + if (sppsm1.getSampleSize(i) != 8) { + return null; + } + } + + ret.channelsOrder = new int[ret.channels]; + int bitOffsets[] = sppsm1.getBitOffsets(); + for (int i = 0; i < ret.channels; i++) { + if (bitOffsets[i] % 8 != 0) { + return null; + } + + ret.channelsOrder[i] = bitOffsets[i] / 8; + } + + ret.channels = 4; + ret.stride = sppsm1.getScanlineStride() * 4; + } else { + return null; + } + + return ret; + } + + /** + * Slow filter. + * + * @param src + * the src. + * @param dst + * the dst. + * @return the int. + */ + private final int slowFilter(Raster src, WritableRaster dst) { + int res = 0; + + SampleModelInfo srcInfo, dstInfo; + int offsets[] = null; + + srcInfo = checkSampleModel(src.getSampleModel()); + dstInfo = checkSampleModel(dst.getSampleModel()); + if (srcInfo == null || dstInfo == null) { + return verySlowFilter(src, dst); + } + + // Fill offsets if there's a child raster + if (src.getParent() != null || dst.getParent() != null) { + if (src.getSampleModelTranslateX() != 0 || src.getSampleModelTranslateY() != 0 + || dst.getSampleModelTranslateX() != 0 || dst.getSampleModelTranslateY() != 0) { + offsets = new int[4]; + offsets[0] = -src.getSampleModelTranslateX() + src.getMinX(); + offsets[1] = -src.getSampleModelTranslateY() + src.getMinY(); + offsets[2] = -dst.getSampleModelTranslateX() + dst.getMinX(); + offsets[3] = -dst.getSampleModelTranslateY() + dst.getMinY(); + } + } + + int rmxWidth = (srcInfo.channels + 1); // width of the reordered matrix + float reorderedMatrix[] = new float[rmxWidth * dstInfo.channels]; + for (int j = 0; j < dstInfo.channels; j++) { + if (j >= dstInfo.channelsOrder.length) { + continue; + } + + for (int i = 0; i < srcInfo.channels; i++) { + if (i >= srcInfo.channelsOrder.length) { + break; + } + + reorderedMatrix[dstInfo.channelsOrder[j] * rmxWidth + srcInfo.channelsOrder[i]] = matrix[j][i]; + } + if (mxWidth == rmxWidth) { + reorderedMatrix[(dstInfo.channelsOrder[j] + 1) * rmxWidth - 1] = matrix[j][mxWidth - 1]; + } + } + + Object srcData, dstData; + AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance(); + try { + srcData = dbAccess.getData(src.getDataBuffer()); + dstData = dbAccess.getData(dst.getDataBuffer()); + } catch (IllegalArgumentException e) { + return -1; // Unknown data buffer type + } + + simpleCombineBands(srcData, src.getWidth(), src.getHeight(), srcInfo.stride, + srcInfo.channels, dstData, dstInfo.stride, dstInfo.channels, reorderedMatrix, + offsets); + + return res; + } + + /** + * Very slow filter. + * + * @param src + * the src. + * @param dst + * the dst. + * @return the int. + */ + private int verySlowFilter(Raster src, WritableRaster dst) { + int numBands = src.getNumBands(); + + int srcMinX = src.getMinX(); + int srcY = src.getMinY(); + + int dstMinX = dst.getMinX(); + int dstY = dst.getMinY(); + + int dX = src.getWidth();// < dst.getWidth() ? src.getWidth() : + // dst.getWidth(); + int dY = src.getHeight();// < dst.getHeight() ? src.getHeight() : + // dst.getHeight(); + + float sample; + int srcPixels[] = new int[numBands * dX * dY]; + int dstPixels[] = new int[mxHeight * dX * dY]; + + srcPixels = src.getPixels(srcMinX, srcY, dX, dY, srcPixels); + + if (numBands == mxWidth) { + for (int i = 0, j = 0; i < srcPixels.length; i += numBands) { + for (int dstB = 0; dstB < mxHeight; dstB++) { + sample = 0f; + for (int srcB = 0; srcB < numBands; srcB++) { + sample += matrix[dstB][srcB] * srcPixels[i + srcB]; + } + dstPixels[j++] = (int)sample; + } + } + } else { + for (int i = 0, j = 0; i < srcPixels.length; i += numBands) { + for (int dstB = 0; dstB < mxHeight; dstB++) { + sample = 0f; + for (int srcB = 0; srcB < numBands; srcB++) { + sample += matrix[dstB][srcB] * srcPixels[i + srcB]; + } + dstPixels[j++] = (int)(sample + matrix[dstB][numBands]); + } + } + } + + dst.setPixels(dstMinX, dstY, dX, dY, dstPixels); + + return 0; + } + + // TODO remove when method is used + /** + * Ipp filter. + * + * @param src + * the src. + * @param dst + * the dst. + * @return the int. + */ + @SuppressWarnings("unused") + private int ippFilter(Raster src, WritableRaster dst) { + boolean invertChannels; + boolean inPlace = (src == dst); + int type; + int srcStride, dstStride; + int offsets[] = null; + + int srcBands = src.getNumBands(); + int dstBands = dst.getNumBands(); + + if (dstBands != 3 + || (srcBands != 3 && !(srcBands == 4 && matrix[0][3] == 0 && matrix[1][3] == 0 && matrix[2][3] == 0))) { + return slowFilter(src, dst); + } + + SampleModel srcSM = src.getSampleModel(); + SampleModel dstSM = dst.getSampleModel(); + + if (srcSM instanceof SinglePixelPackedSampleModel + && dstSM instanceof SinglePixelPackedSampleModel) { + // Check SinglePixelPackedSampleModel + SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel)srcSM; + SinglePixelPackedSampleModel sppsm2 = (SinglePixelPackedSampleModel)dstSM; + + if (sppsm1.getDataType() != DataBuffer.TYPE_INT + || sppsm2.getDataType() != DataBuffer.TYPE_INT) { + return slowFilter(src, dst); + } + + // Check sample models + if (!Arrays.equals(sppsm2.getBitOffsets(), offsets3c) + || !Arrays.equals(sppsm2.getBitMasks(), masks3c)) { + return slowFilter(src, dst); + } + + if (srcBands == 3) { + if (!Arrays.equals(sppsm1.getBitOffsets(), offsets3c) + || !Arrays.equals(sppsm1.getBitMasks(), masks3c)) { + return slowFilter(src, dst); + } + } else if (srcBands == 4) { + if (!Arrays.equals(sppsm1.getBitOffsets(), offsets4ac) + || !Arrays.equals(sppsm1.getBitMasks(), masks4ac)) { + return slowFilter(src, dst); + } + } + + type = TYPE_BYTE4AC; + invertChannels = true; + + srcStride = sppsm1.getScanlineStride() * 4; + dstStride = sppsm2.getScanlineStride() * 4; + } else if (srcSM instanceof PixelInterleavedSampleModel + && dstSM instanceof PixelInterleavedSampleModel) { + if (srcBands != 3) { + return slowFilter(src, dst); + } + + int srcDataType = srcSM.getDataType(); + + switch (srcDataType) { + case DataBuffer.TYPE_BYTE: + type = TYPE_BYTE3C; + break; + case DataBuffer.TYPE_USHORT: + type = TYPE_USHORT3C; + break; + case DataBuffer.TYPE_SHORT: + type = TYPE_SHORT3C; + break; + default: + return slowFilter(src, dst); + } + + // Check PixelInterleavedSampleModel + PixelInterleavedSampleModel pism1 = (PixelInterleavedSampleModel)srcSM; + PixelInterleavedSampleModel pism2 = (PixelInterleavedSampleModel)dstSM; + + if (srcDataType != pism2.getDataType() || pism1.getPixelStride() != 3 + || pism2.getPixelStride() != 3 + || !Arrays.equals(pism1.getBandOffsets(), pism2.getBandOffsets())) { + return slowFilter(src, dst); + } + + if (Arrays.equals(pism1.getBandOffsets(), piInvOffsets)) { + invertChannels = true; + } else if (Arrays.equals(pism1.getBandOffsets(), piOffsets)) { + invertChannels = false; + } else { + return slowFilter(src, dst); + } + + int dataTypeSize = DataBuffer.getDataTypeSize(srcDataType) / 8; + + srcStride = pism1.getScanlineStride() * dataTypeSize; + dstStride = pism2.getScanlineStride() * dataTypeSize; + } else { // XXX - todo - IPP allows support for planar data also + return slowFilter(src, dst); + } + + // Fill offsets if there's a child raster + if (src.getParent() != null || dst.getParent() != null) { + if (src.getSampleModelTranslateX() != 0 || src.getSampleModelTranslateY() != 0 + || dst.getSampleModelTranslateX() != 0 || dst.getSampleModelTranslateY() != 0) { + offsets = new int[4]; + offsets[0] = -src.getSampleModelTranslateX() + src.getMinX(); + offsets[1] = -src.getSampleModelTranslateY() + src.getMinY(); + offsets[2] = -dst.getSampleModelTranslateX() + dst.getMinX(); + offsets[3] = -dst.getSampleModelTranslateY() + dst.getMinY(); + } + } + + Object srcData, dstData; + AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance(); + try { + srcData = dbAccess.getData(src.getDataBuffer()); + dstData = dbAccess.getData(dst.getDataBuffer()); + } catch (IllegalArgumentException e) { + return -1; // Unknown data buffer type + } + + float ippMatrix[] = new float[12]; + + if (invertChannels) { + // IPP treats big endian integers like BGR, so we have to + // swap columns 1 and 3 and rows 1 and 3 + for (int i = 0; i < mxHeight; i++) { + ippMatrix[i * 4] = matrix[2 - i][2]; + ippMatrix[i * 4 + 1] = matrix[2 - i][1]; + ippMatrix[i * 4 + 2] = matrix[2 - i][0]; + + if (mxWidth == 4) { + ippMatrix[i * 4 + 3] = matrix[2 - i][3]; + } else if (mxWidth == 5) { + ippMatrix[i * 4 + 3] = matrix[2 - i][4]; + } + } + } else { + for (int i = 0; i < mxHeight; i++) { + ippMatrix[i * 4] = matrix[i][0]; + ippMatrix[i * 4 + 1] = matrix[i][1]; + ippMatrix[i * 4 + 2] = matrix[i][2]; + + if (mxWidth == 4) { + ippMatrix[i * 4 + 3] = matrix[i][3]; + } else if (mxWidth == 5) { + ippMatrix[i * 4 + 3] = matrix[i][4]; + } + } + } + + return ippColorTwist(srcData, src.getWidth(), src.getHeight(), srcStride, dstData, dst + .getWidth(), dst.getHeight(), dstStride, ippMatrix, type, offsets, inPlace); + } + + /** + * Ipp color twist. + * + * @param srcData + * the src data. + * @param srcWidth + * the src width. + * @param srcHeight + * the src height. + * @param srcStride + * the src stride. + * @param dstData + * the dst data. + * @param dstWidth + * the dst width. + * @param dstHeight + * the dst height. + * @param dstStride + * the dst stride. + * @param ippMatrix + * the ipp matrix. + * @param type + * the type. + * @param offsets + * the offsets. + * @param inPlace + * the in place. + * @return the int. + */ + private final native int ippColorTwist(Object srcData, int srcWidth, int srcHeight, + int srcStride, Object dstData, int dstWidth, int dstHeight, int dstStride, + float ippMatrix[], int type, int offsets[], boolean inPlace); + + /** + * Simple combine bands. + * + * @param srcData + * the src data. + * @param srcWidth + * the src width. + * @param srcHeight + * the src height. + * @param srcStride + * the src stride. + * @param srcChannels + * the src channels. + * @param dstData + * the dst data. + * @param dstStride + * the dst stride. + * @param dstChannels + * the dst channels. + * @param m + * the m. + * @param offsets + * the offsets. + * @return the int. + */ + private final native int simpleCombineBands(Object srcData, int srcWidth, int srcHeight, + int srcStride, int srcChannels, Object dstData, int dstStride, int dstChannels, + float m[], int offsets[]); +} diff --git a/app/src/main/java/java/awt/image/BandedSampleModel.java b/app/src/main/java/java/awt/image/BandedSampleModel.java new file mode 100644 index 000000000..0aa30d7da --- /dev/null +++ b/app/src/main/java/java/awt/image/BandedSampleModel.java @@ -0,0 +1,425 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The BandedSampleModel class provides samples of pixels in an image which is + * stored in a band interleaved method. Each pixel's sample takes one data + * element of the DataBuffer. The pixel stride for a BandedSampleModel is one. + * + * @since Android 1.0 + */ +public final class BandedSampleModel extends ComponentSampleModel { + + /** + * Creates the indices. + * + * @param numBands + * the num bands. + * @return the int[]. + */ + private static int[] createIndices(int numBands) { + int indices[] = new int[numBands]; + for (int i = 0; i < numBands; i++) { + indices[i] = i; + } + return indices; + } + + /** + * Creates the offsets. + * + * @param numBands + * the num bands. + * @return the int[]. + */ + private static int[] createOffsets(int numBands) { + int offsets[] = new int[numBands]; + for (int i = 0; i < numBands; i++) { + offsets[i] = 0; + } + return offsets; + } + + /** + * Instantiates a new BandedSampleModel object with the specified data type + * of samples, the width, height and bands number of image data. + * + * @param dataType + * the data type of samples. + * @param w + * the width of image data. + * @param h + * the height of image data. + * @param numBands + * the number of bands. + */ + public BandedSampleModel(int dataType, int w, int h, int numBands) { + this(dataType, w, h, w, BandedSampleModel.createIndices(numBands), BandedSampleModel + .createOffsets(numBands)); + } + + /** + * Instantiates a new BandedSampleModel object with the specified data type + * of samples, the width, height and bands number of image data. + * + * @param dataType + * the data type of samples. + * @param w + * the width of image data. + * @param h + * the height of image data. + * @param scanlineStride + * the scanline stride of the of the image data. + * @param bankIndices + * the array of the bank indices. + * @param bandOffsets + * the array of the band offsets. + */ + public BandedSampleModel(int dataType, int w, int h, int scanlineStride, int bankIndices[], + int bandOffsets[]) { + super(dataType, w, h, 1, scanlineStride, bankIndices, bandOffsets); + } + + @Override + public SampleModel createCompatibleSampleModel(int w, int h) { + return new BandedSampleModel(dataType, w, h, w, bankIndices, bandOffsets); + } + + @Override + public DataBuffer createDataBuffer() { + DataBuffer data = null; + int size = scanlineStride * height; + + switch (dataType) { + case DataBuffer.TYPE_BYTE: + data = new DataBufferByte(size, numBanks); + break; + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: + data = new DataBufferShort(size, numBanks); + break; + case DataBuffer.TYPE_INT: + data = new DataBufferInt(size, numBanks); + break; + case DataBuffer.TYPE_FLOAT: + data = new DataBufferFloat(size, numBanks); + break; + case DataBuffer.TYPE_DOUBLE: + data = new DataBufferDouble(size, numBanks); + break; + } + + return data; + + } + + @Override + public SampleModel createSubsetSampleModel(int[] bands) { + if (bands.length > numBands) { + // awt.64=The number of the bands in the subset is greater than the + // number of bands in the sample model + throw new RasterFormatException(Messages.getString("awt.64")); //$NON-NLS-1$ + } + + int indices[] = new int[bands.length]; + int offsets[] = new int[bands.length]; + + for (int i = 0; i < bands.length; i++) { + indices[i] = bankIndices[bands[i]]; + offsets[i] = bandOffsets[bands[i]]; + } + + return new BandedSampleModel(dataType, width, height, scanlineStride, indices, offsets); + } + + @Override + public Object getDataElements(int x, int y, Object obj, DataBuffer data) { + switch (dataType) { + case DataBuffer.TYPE_BYTE: { + byte bdata[]; + + if (obj == null) { + bdata = new byte[numBands]; + } else { + bdata = (byte[])obj; + } + + for (int i = 0; i < numBands; i++) { + bdata[i] = (byte)getSample(x, y, i, data); + } + + obj = bdata; + break; + } + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: { + short sdata[]; + + if (obj == null) { + sdata = new short[numBands]; + } else { + sdata = (short[])obj; + } + + for (int i = 0; i < numBands; i++) { + sdata[i] = (short)getSample(x, y, i, data); + } + + obj = sdata; + break; + } + case DataBuffer.TYPE_INT: { + int idata[]; + + if (obj == null) { + idata = new int[numBands]; + } else { + idata = (int[])obj; + } + + for (int i = 0; i < numBands; i++) { + idata[i] = getSample(x, y, i, data); + } + + obj = idata; + break; + } + case DataBuffer.TYPE_FLOAT: { + float fdata[]; + + if (obj == null) { + fdata = new float[numBands]; + } else { + fdata = (float[])obj; + } + + for (int i = 0; i < numBands; i++) { + fdata[i] = getSampleFloat(x, y, i, data); + } + + obj = fdata; + break; + } + case DataBuffer.TYPE_DOUBLE: { + double ddata[]; + + if (obj == null) { + ddata = new double[numBands]; + } else { + ddata = (double[])obj; + } + + for (int i = 0; i < numBands; i++) { + ddata[i] = getSampleDouble(x, y, i, data); + } + + obj = ddata; + break; + } + } + + return obj; + } + + @Override + public int[] getPixel(int x, int y, int iArray[], DataBuffer data) { + int pixel[]; + if (iArray == null) { + pixel = new int[numBands]; + } else { + pixel = iArray; + } + + for (int i = 0; i < numBands; i++) { + pixel[i] = getSample(x, y, i, data); + } + + return pixel; + } + + @Override + public int getSample(int x, int y, int b, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + return data.getElem(bankIndices[b], y * scanlineStride + x + bandOffsets[b]); + } + + @Override + public double getSampleDouble(int x, int y, int b, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + return data.getElemDouble(bankIndices[b], y * scanlineStride + x + bandOffsets[b]); + } + + @Override + public float getSampleFloat(int x, int y, int b, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + return data.getElemFloat(bankIndices[b], y * scanlineStride + x + bandOffsets[b]); + } + + @Override + public int[] getSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) { + int samples[]; + int idx = 0; + + if (iArray == null) { + samples = new int[w * h]; + } else { + samples = iArray; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + samples[idx++] = getSample(j, i, b, data); + } + } + + return samples; + } + + @Override + public int hashCode() { + int hash = super.hashCode(); + int tmp = hash >>> 8; + hash <<= 8; + hash |= tmp; + + return hash ^ 0x55; + } + + @Override + public void setDataElements(int x, int y, Object obj, DataBuffer data) { + switch (dataType) { + case DataBuffer.TYPE_BYTE: + byte bdata[] = (byte[])obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, bdata[i] & 0xff, data); + } + break; + + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: + short sdata[] = (short[])obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, sdata[i] & 0xffff, data); + } + break; + + case DataBuffer.TYPE_INT: + int idata[] = (int[])obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, idata[i], data); + } + break; + + case DataBuffer.TYPE_FLOAT: + float fdata[] = (float[])obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, fdata[i], data); + } + break; + + case DataBuffer.TYPE_DOUBLE: + double ddata[] = (double[])obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, ddata[i], data); + } + break; + } + } + + @Override + public void setPixel(int x, int y, int iArray[], DataBuffer data) { + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, iArray[i], data); + } + } + + @Override + public void setPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) { + int idx = 0; + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numBands; n++) { + setSample(j, i, n, iArray[idx++], data); + } + } + } + } + + @Override + public void setSample(int x, int y, int b, double s, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + data.setElemDouble(bankIndices[b], y * scanlineStride + x + bandOffsets[b], s); + } + + @Override + public void setSample(int x, int y, int b, float s, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + data.setElemFloat(bankIndices[b], y * scanlineStride + x + bandOffsets[b], s); + } + + @Override + public void setSample(int x, int y, int b, int s, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + data.setElem(bankIndices[b], y * scanlineStride + x + bandOffsets[b], s); + } + + @Override + public void setSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) { + int idx = 0; + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + setSample(j, i, b, iArray[idx++], data); + } + } + + } + +} diff --git a/app/src/main/java/java/awt/image/BufferStrategy.java b/app/src/main/java/java/awt/image/BufferStrategy.java new file mode 100644 index 000000000..3c8779dac --- /dev/null +++ b/app/src/main/java/java/awt/image/BufferStrategy.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.awt.BufferCapabilities; +import java.awt.Graphics; + +/** + * The BufferStrategy abstract class provides an opportunity to organize the + * buffers for a Canvas or Window. The BufferStrategy implementation depends on + * hardware and software limitations. These limitations are detectable through + * the capabilities object which can be obtained by the GraphicsConfiguration of + * the Canvas or Window. + * + * @since Android 1.0 + */ +public abstract class BufferStrategy { + + /** + * Returns true if the drawing buffer was lost since the last call of + * getDrawGraphics. + * + * @return true if the drawing buffer was lost since the last call of + * getDrawGraphics, false otherwise. + */ + public abstract boolean contentsLost(); + + /** + * Returns true if the drawing buffer is restored from a lost state. + * + * @return true if the drawing buffer is restored from a lost state, false + * otherwise. + */ + public abstract boolean contentsRestored(); + + /** + * Gets the BufferCapabilities of BufferStrategy. + * + * @return the BufferCapabilities of BufferStrategy. + */ + public abstract BufferCapabilities getCapabilities(); + + /** + * Gets the Graphics object to use to draw to the buffer. + * + * @return the Graphics object to use to draw to the buffer. + */ + public abstract Graphics getDrawGraphics(); + + /** + * Shows the next available buffer. + */ + public abstract void show(); + +} diff --git a/app/src/main/java/java/awt/image/BufferedImage.java b/app/src/main/java/java/awt/image/BufferedImage.java index e5d2a3fa5..da5711b05 100644 --- a/app/src/main/java/java/awt/image/BufferedImage.java +++ b/app/src/main/java/java/awt/image/BufferedImage.java @@ -1,88 +1,952 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + package java.awt.image; -import android.graphics.Bitmap; -import android.graphics.Bitmap.Config; +import com.android.internal.awt.AndroidGraphics2D; + import java.awt.Graphics; import java.awt.Graphics2D; +import java.awt.GraphicsEnvironment; import java.awt.Image; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Transparency; +import java.awt.color.ColorSpace; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; -public class BufferedImage extends Image implements RenderedImage { +import org.apache.harmony.awt.gl.ImageSurface; +import org.apache.harmony.awt.gl.Surface; +import org.apache.harmony.awt.gl.image.BufferedImageSource; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The BufferedImage class describes an Image which contains a buffer of image + * data and includes a ColorModel and a Raster for this data. This class + * provides methods for obtaining and setting the Raster and for manipulating + * the ColorModel parameters. + * + * @since Android 1.0 + */ +public class BufferedImage extends Image implements WritableRenderedImage, Transparency { + + /** + * The Constant TYPE_CUSTOM indicates that Image type is unknown. + */ + public static final int TYPE_CUSTOM = 0; + + /** + * The Constant TYPE_INT_RGB indicates an image with 8 bit RGB color + * components, it has a DirectColorModel without alpha. + */ + public static final int TYPE_INT_RGB = 1; + + /** + * The Constant TYPE_INT_ARGB indicates an image with 8 bit RGBA color + * components, it has a DirectColorModel with alpha. + */ public static final int TYPE_INT_ARGB = 2; - private Bitmap bitmap; - private WritableRaster raster; - private Bitmap mkBitmap(int width, int height, Config mode) { - return Bitmap.createBitmap(width, height, mode); - } - public BufferedImage(Bitmap bitmap) { - if (bitmap != null) { - this.bitmap = bitmap; - } else { - mkBitmap(1, 1, Config.ARGB_8888); - } - init(); - } + /** + * The Constant TYPE_INT_ARGB_PRE indicates an image with 8 bit RGBA color + * components, it has a DirectColorModel with alpha, and image data is + * pre-multiplied by alpha. + */ + public static final int TYPE_INT_ARGB_PRE = 3; - public BufferedImage(int width, int height, int imageType) { - this.bitmap = mkBitmap(width, height, Config.ARGB_8888); - /* - if (imageType == TYPE_INT_ARGB) { - this.bitmap = mkBitmap(width, height, Config.ARGB_8888); - } else { - this.bitmap = mkBitmap(width, height, Config.HARDWARE); - } - */ - init(); - } - - public void init() { - raster = new WritableRaster(this); - } + /** + * The Constant TYPE_INT_BGR indicates an image with 8 bit RGB color + * components, BGR color model (with the colors Blue, Green, and Red). There + * is no alpha. The image has a DirectColorModel. + */ + public static final int TYPE_INT_BGR = 4; - public int getWidth() { - return this.bitmap.getWidth(); - } + /** + * The Constant TYPE_3BYTE_BGR indicates an image with 8 bit RGB color + * components, BGR color model (with the colors Blue, Green, and Red stored + * in 3 bytes). There is no alpha. The image has a ComponentColorModel. + */ + public static final int TYPE_3BYTE_BGR = 5; - public int getHeight() { - return this.bitmap.getHeight(); - } + /** + * The Constant TYPE_4BYTE_ABGR indicates an image with 8 bit RGBA color + * components stored in 3 bytes and 1 byte of alpha. It has a + * ComponentColorModel with alpha. + */ + public static final int TYPE_4BYTE_ABGR = 6; - public int[] getRGB(int x, int y, int w, int h, int[] rgbArray, int offset, int scansize) { - if (rgbArray == null) { - rgbArray = new int[((scansize * h) + offset)]; + /** + * The Constant TYPE_4BYTE_ABGR_PRE indicates an image with 8 bit RGBA color + * components stored in 3 bytes and 1 byte for alpha. The image has a + * ComponentColorModel with alpha. The color data is pre-multiplied with + * alpha. + */ + public static final int TYPE_4BYTE_ABGR_PRE = 7; + + /** + * The Constant TYPE_USHORT_565_RGB indicates an image with 565 RGB color + * components (5-bits red, 6-bits green, 5-bits blue) with no alpha. This + * image has a DirectColorModel. + */ + public static final int TYPE_USHORT_565_RGB = 8; + + /** + * The Constant TYPE_USHORT_555_RGB indicates an image with 555 RGB color + * components (5-bits red, 5-bits green, 5-bits blue) with no alpha. This + * image has a DirectColorModel. + */ + public static final int TYPE_USHORT_555_RGB = 9; + + /** + * The Constant TYPE_BYTE_GRAY indicates a unsigned byte image. This image + * has a ComponentColorModel with a CS_GRAY ColorSpace. + */ + public static final int TYPE_BYTE_GRAY = 10; + + /** + * The Constant TYPE_USHORT_GRAY indicates an unsigned short image. This + * image has a ComponentColorModel with a CS_GRAY ColorSpace. + */ + public static final int TYPE_USHORT_GRAY = 11; + + /** + * The Constant TYPE_BYTE_BINARY indicates an opaque byte-packed 1, 2 or 4 + * bit image. The image has an IndexColorModel without alpha. + */ + public static final int TYPE_BYTE_BINARY = 12; + + /** + * The Constant TYPE_BYTE_INDEXED indicates an indexed byte image. + */ + public static final int TYPE_BYTE_INDEXED = 13; + + /** + * The Constant ALPHA_MASK. + */ + private static final int ALPHA_MASK = 0xff000000; + + /** + * The Constant RED_MASK. + */ + private static final int RED_MASK = 0x00ff0000; + + /** + * The Constant GREEN_MASK. + */ + private static final int GREEN_MASK = 0x0000ff00; + + /** + * The Constant BLUE_MASK. + */ + private static final int BLUE_MASK = 0x000000ff; + + /** + * The Constant RED_BGR_MASK. + */ + private static final int RED_BGR_MASK = 0x000000ff; + + /** + * The Constant GREEN_BGR_MASK. + */ + private static final int GREEN_BGR_MASK = 0x0000ff00; + + /** + * The Constant BLUE_BGR_MASK. + */ + private static final int BLUE_BGR_MASK = 0x00ff0000; + + /** + * The Constant RED_565_MASK. + */ + private static final int RED_565_MASK = 0xf800; + + /** + * The Constant GREEN_565_MASK. + */ + private static final int GREEN_565_MASK = 0x07e0; + + /** + * The Constant BLUE_565_MASK. + */ + private static final int BLUE_565_MASK = 0x001f; + + /** + * The Constant RED_555_MASK. + */ + private static final int RED_555_MASK = 0x7c00; + + /** + * The Constant GREEN_555_MASK. + */ + private static final int GREEN_555_MASK = 0x03e0; + + /** + * The Constant BLUE_555_MASK. + */ + private static final int BLUE_555_MASK = 0x001f; + + /** + * The cm. + */ + private ColorModel cm; + + /** + * The raster. + */ + private final WritableRaster raster; + + /** + * The image type. + */ + private final int imageType; + + /** + * The properties. + */ + private Hashtable properties; + + // Surface of the Buffered Image - used for blitting one Buffered Image + // on the other one or on the Component + /** + * The image surf. + */ + private final ImageSurface imageSurf; + + /** + * Instantiates a new BufferedImage with the specified ColorModel, and + * WritableRaster objects. The Raster data can be be divided or multiplied + * by alpha. It depends on the alphaPremultiplied state in the ColorModel. + * + * @param cm + * the ColorModel of the new image. + * @param raster + * the WritableRaster of the new image. + * @param isRasterPremultiplied + * if true the data of the specified Raster is pre-multiplied by + * alpha. + * @param properties + * the properties of new Image. + */ + public BufferedImage(ColorModel cm, WritableRaster raster, boolean isRasterPremultiplied, + Hashtable properties) { + if (!cm.isCompatibleRaster(raster)) { + // awt.4D=The raster is incompatible with this ColorModel + throw new IllegalArgumentException(Messages.getString("awt.4D")); //$NON-NLS-1$ } - this.bitmap.getPixels(rgbArray, offset, scansize, x, y, w, h); - return rgbArray; + + if (raster.getMinX() != 0 || raster.getMinY() != 0) { + // awt.228=minX or minY of this raster not equal to zero + throw new IllegalArgumentException(Messages.getString("awt.228")); //$NON-NLS-1$ + } + + this.cm = cm; + this.raster = raster; + this.properties = properties; + + coerceData(isRasterPremultiplied); + + imageType = Surface.getType(cm, raster); + + imageSurf = createImageSurface(imageType); } - public Graphics getGraphics() { - return new Graphics2D(this); + /** + * Instantiates a new BufferedImage with the specified width, height + * predefined image type (TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED) and the + * specified IndexColorModel. + * + * @param width + * the width of new image. + * @param height + * the height of new image. + * @param imageType + * the predefined image type. + * @param cm + * the specified IndexColorModel. + */ + public BufferedImage(int width, int height, int imageType, IndexColorModel cm) { + switch (imageType) { + case TYPE_BYTE_BINARY: + if (cm.hasAlpha()) { + // awt.227=This image type can't have alpha + throw new IllegalArgumentException(Messages.getString("awt.227")); //$NON-NLS-1$ + } + int pixel_bits = 0; + int mapSize = cm.getMapSize(); + if (mapSize <= 2) { + pixel_bits = 1; + } else if (mapSize <= 4) { + pixel_bits = 2; + } else if (mapSize <= 16) { + pixel_bits = 4; + } else { + // awt.221=The imageType is TYPE_BYTE_BINARY and the color + // map has more than 16 entries + throw new IllegalArgumentException(Messages.getString("awt.221")); //$NON-NLS-1$ + } + + raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, width, height, 1, + pixel_bits, null); + break; + + case TYPE_BYTE_INDEXED: + raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, 1, + null); + break; + + default: + // awt.222=The imageType is not TYPE_BYTE_BINARY or + // TYPE_BYTE_INDEXED + throw new IllegalArgumentException(Messages.getString("awt.222")); //$NON-NLS-1$ + + } + + if (!cm.isCompatibleRaster(raster)) { + // awt.223=The imageType is not compatible with ColorModel + throw new IllegalArgumentException(Messages.getString("awt.223")); //$NON-NLS-1$ + } + + this.cm = cm; + this.imageType = imageType; + imageSurf = createImageSurface(imageType); + } - public Graphics2D createGraphics() { - return new Graphics2D(this); + /** + * Instantiates a new BufferedImage with the specified width, height and + * predefined image type. + * + * @param width + * the width of new image. + * @param height + * the height of new image. + * @param imageType + * the predefined image type. + */ + public BufferedImage(int width, int height, int imageType) { + + switch (imageType) { + case TYPE_INT_RGB: + cm = new DirectColorModel(24, RED_MASK, GREEN_MASK, BLUE_MASK); + raster = cm.createCompatibleWritableRaster(width, height); + break; + + case TYPE_INT_ARGB: + cm = ColorModel.getRGBdefault(); + raster = cm.createCompatibleWritableRaster(width, height); + break; + + case TYPE_INT_ARGB_PRE: + cm = new DirectColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), 32, RED_MASK, + GREEN_MASK, BLUE_MASK, ALPHA_MASK, true, DataBuffer.TYPE_INT); + + raster = cm.createCompatibleWritableRaster(width, height); + break; + + case TYPE_INT_BGR: + cm = new DirectColorModel(24, RED_BGR_MASK, GREEN_BGR_MASK, BLUE_BGR_MASK); + + raster = cm.createCompatibleWritableRaster(width, height); + break; + + case TYPE_3BYTE_BGR: { + int bits[] = { + 8, 8, 8 + }; + int bandOffsets[] = { + 2, 1, 0 + }; + cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), bits, + false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE); + + raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, + width * 3, 3, bandOffsets, null); + } + break; + + case TYPE_4BYTE_ABGR: { + int bits[] = { + 8, 8, 8, 8 + }; + int bandOffsets[] = { + 3, 2, 1, 0 + }; + cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), bits, + true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE); + + raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, + width * 4, 4, bandOffsets, null); + } + break; + + case TYPE_4BYTE_ABGR_PRE: { + int bits[] = { + 8, 8, 8, 8 + }; + int bandOffsets[] = { + 3, 2, 1, 0 + }; + cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), bits, + true, true, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE); + + raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, + width * 4, 4, bandOffsets, null); + } + break; + + case TYPE_USHORT_565_RGB: + cm = new DirectColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), 16, + RED_565_MASK, GREEN_565_MASK, BLUE_565_MASK, 0, false, + DataBuffer.TYPE_USHORT); + + raster = cm.createCompatibleWritableRaster(width, height); + break; + + case TYPE_USHORT_555_RGB: + cm = new DirectColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), 15, + RED_555_MASK, GREEN_555_MASK, BLUE_555_MASK, 0, false, + DataBuffer.TYPE_USHORT); + + raster = cm.createCompatibleWritableRaster(width, height); + break; + + case TYPE_BYTE_GRAY: { + int bits[] = { + 8 + }; + cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY), bits, + false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE); + + raster = cm.createCompatibleWritableRaster(width, height); + } + break; + + case TYPE_USHORT_GRAY: { + int bits[] = { + 16 + }; + cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY), bits, + false, false, Transparency.OPAQUE, DataBuffer.TYPE_USHORT); + raster = cm.createCompatibleWritableRaster(width, height); + } + break; + + case TYPE_BYTE_BINARY: { + int colorMap[] = { + 0, 0xffffff + }; + cm = new IndexColorModel(1, 2, colorMap, 0, false, -1, DataBuffer.TYPE_BYTE); + + raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, width, height, 1, 1, null); + } + break; + + case TYPE_BYTE_INDEXED: { + int colorMap[] = new int[256]; + int i = 0; + for (int r = 0; r < 256; r += 51) { + for (int g = 0; g < 256; g += 51) { + for (int b = 0; b < 256; b += 51) { + colorMap[i] = (r << 16) | (g << 8) | b; + i++; + } + } + } + + int gray = 0x12; + for (; i < 256; i++, gray += 6) { + colorMap[i] = (gray << 16) | (gray << 8) | gray; + } + cm = new IndexColorModel(8, 256, colorMap, 0, false, -1, DataBuffer.TYPE_BYTE); + raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, 1, + null); + + } + break; + default: + // awt.224=Unknown image type + throw new IllegalArgumentException(Messages.getString("awt.224")); //$NON-NLS-1$ + } + this.imageType = imageType; + imageSurf = createImageSurface(imageType); } - public void setRGB(int x, int y, int w, int h, int[] rgbArray, int offset, int scansize) { - System.out.println("Setting RGB stub"); - - if (rgbArray == null) { - int size = (h - 1) * scansize + w; - rgbArray = new int[size]; - } - bitmap.setPixels(rgbArray, offset, scansize, x, y, w, h); + @Override + public Object getProperty(String name, ImageObserver observer) { + return getProperty(name); } + public Object getProperty(String name) { + if (name == null) { + // awt.225=Property name is null + throw new NullPointerException(Messages.getString("awt.225")); //$NON-NLS-1$ + } + if (properties == null) { + return Image.UndefinedProperty; + } + Object property = properties.get(name); + if (property == null) { + property = Image.UndefinedProperty; + } + return property; + } + + public WritableRaster copyData(WritableRaster outRaster) { + if (outRaster == null) { + outRaster = Raster.createWritableRaster(raster.getSampleModel(), new Point(raster + .getSampleModelTranslateX(), raster.getSampleModelTranslateY())); + } + + int w = outRaster.getWidth(); + int h = outRaster.getHeight(); + int minX = outRaster.getMinX(); + int minY = outRaster.getMinY(); + + Object data = null; + + data = raster.getDataElements(minX, minY, w, h, data); + outRaster.setDataElements(minX, minY, w, h, data); + + return outRaster; + } + + public Raster getData(Rectangle rect) { + int minX = rect.x; + int minY = rect.y; + int w = rect.width; + int h = rect.height; + + SampleModel sm = raster.getSampleModel(); + SampleModel nsm = sm.createCompatibleSampleModel(w, h); + WritableRaster outr = Raster.createWritableRaster(nsm, rect.getLocation()); + Object data = null; + + data = raster.getDataElements(minX, minY, w, h, data); + outr.setDataElements(minX, minY, w, h, data); + return outr; + } + + public Vector getSources() { + return null; + } + + public String[] getPropertyNames() { + if (properties == null) { + return null; + } + Vector v = new Vector(); + for (Enumeration e = properties.keys(); e.hasMoreElements();) { + try { + v.add((String)e.nextElement()); + } catch (ClassCastException ex) { + } + } + int size = v.size(); + if (size > 0) { + String names[] = new String[size]; + for (int i = 0; i < size; i++) { + names[i] = v.elementAt(i); + } + return names; + } + return null; + } + + /** + * Returns the string representation of this BufferedImage object. + * + * @return the string representation of this BufferedImage object. + */ + @Override + public String toString() { + return "BufferedImage@" + Integer.toHexString(hashCode()) + //$NON-NLS-1$ + ": type = " + imageType + " " + cm + " " + raster; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + public WritableRaster getWritableTile(int tileX, int tileY) { + return raster; + } + + /** + * Gets the WritableRaster of this BufferedImage. + * + * @return the WritableRaster of this BufferedImage. + */ public WritableRaster getRaster() { return raster; } - public Bitmap getAndroidBitmap() { - return this.bitmap; + /** + * Gets a WritableRaster object which contains the alpha channel of + * BufferedImage object with ColorModel objects that supports a separate + * alpha channel such as ComponentColorModel or DirectColorModel. + * + * @return the WritableRaster object which contains the alpha channel of + * this BufferedImage. + */ + public WritableRaster getAlphaRaster() { + return cm.getAlphaRaster(raster); } + public void removeTileObserver(TileObserver to) { + } + + public void addTileObserver(TileObserver to) { + } + + public SampleModel getSampleModel() { + return raster.getSampleModel(); + } + + public void setData(Raster r) { + + Rectangle from = r.getBounds(); + Rectangle to = raster.getBounds(); + Rectangle intersection = to.intersection(from); + + int minX = intersection.x; + int minY = intersection.y; + int w = intersection.width; + int h = intersection.height; + + Object data = null; + + data = r.getDataElements(minX, minY, w, h, data); + raster.setDataElements(minX, minY, w, h, data); + } + + public Raster getTile(int tileX, int tileY) { + if (tileX == 0 && tileY == 0) { + return raster; + } + // awt.226=Both tileX and tileY are not equal to 0 + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.226")); //$NON-NLS-1$ + } + + public Raster getData() { + int w = raster.getWidth(); + int h = raster.getHeight(); + int minX = raster.getMinX(); + int minY = raster.getMinY(); + + WritableRaster outr = Raster.createWritableRaster(raster.getSampleModel(), new Point(raster + .getSampleModelTranslateX(), raster.getSampleModelTranslateY())); + + Object data = null; + + data = raster.getDataElements(minX, minY, w, h, data); + outr.setDataElements(minX, minY, w, h, data); + + return outr; + } + + @Override + public ImageProducer getSource() { + return new BufferedImageSource(this, properties); + } + + @Override + public int getWidth(ImageObserver observer) { + return raster.getWidth(); + } + + @Override + public int getHeight(ImageObserver observer) { + return raster.getHeight(); + } + + public ColorModel getColorModel() { + return cm; + } + + /** + * Gets the rectangular area of this BufferedImage as a subimage. + * + * @param x + * the x coordinate. + * @param y + * the y coordinate. + * @param w + * the width of the subimage. + * @param h + * the height of the subimage. + * @return the BufferedImage. + */ + public BufferedImage getSubimage(int x, int y, int w, int h) { + WritableRaster wr = raster.createWritableChild(x, y, w, h, 0, 0, null); + return new BufferedImage(cm, wr, cm.isAlphaPremultiplied(), properties); + } + + public Point[] getWritableTileIndices() { + Point points[] = new Point[1]; + points[0] = new Point(0, 0); + return points; + } + + /** + * Creates the Graphics2D object which allows to draw into this + * BufferedImage. + * + * @return the graphics2D object. + */ + public Graphics2D createGraphics() { + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + // return ge.createGraphics(this); + // ???AWT hack, FIXME + return AndroidGraphics2D.getInstance(); + // throw new RuntimeException("Not implemented!"); + // return null; + } + + @Override + public Graphics getGraphics() { + return createGraphics(); + } + + /** + * Coerces the data to achieve the state which is specified by the + * isAlphaPremultiplied variable. + * + * @param isAlphaPremultiplied + * the is alpha pre-multiplied state. + */ + public void coerceData(boolean isAlphaPremultiplied) { + if (cm.hasAlpha() && cm.isAlphaPremultiplied() != isAlphaPremultiplied) { + cm = cm.coerceData(raster, isAlphaPremultiplied); + } + } + + /** + * Gets an array of colors in the TYPE_INT_ARGB color model and default sRGB + * color space of the specified area of this BufferedImage. The result array + * is composed by the following algorithm: + *

+ * pixel = rgbArray[offset + (y-startY)*scansize + (x-startX)] + *

+ * + * @param startX + * the start X area coordinate. + * @param startY + * the start Y area coordinate. + * @param w + * the width of the area. + * @param h + * the height of the area. + * @param rgbArray + * the result array will be stored to this array. + * @param offset + * the offset of the rgbArray array. + * @param scansize + * the scanline stride for the rgbArray. + * @return an array of colors for the specified area. + */ + public int[] getRGB(int startX, int startY, int w, int h, int[] rgbArray, int offset, + int scansize) { + if (rgbArray == null) { + rgbArray = new int[offset + h * scansize]; + } + + int off = offset; + for (int y = startY; y < startY + h; y++, off += scansize) { + int i = off; + for (int x = startX; x < startX + w; x++, i++) { + rgbArray[i] = cm.getRGB(raster.getDataElements(x, y, null)); + } + } + return rgbArray; + } + + /** + * Sets RGB values from the specified array to the specified BufferedImage + * area. The pixels are in the default RGB color model (TYPE_INT_ARGB) and + * default sRGB color space. + * + * @param startX + * the start X coordinate. + * @param startY + * the start Y coordinate. + * @param w + * the width of the BufferedImage area. + * @param h + * the height of the BufferedImage area. + * @param rgbArray + * the array of RGB values. + * @param offset + * the offset of the rgbArray array. + * @param scansize + * the scanline stride for the rgbArray. + */ + public void setRGB(int startX, int startY, int w, int h, int[] rgbArray, int offset, + int scansize) { + int off = offset; + for (int y = startY; y < startY + h; y++, off += scansize) { + int i = off; + for (int x = startX; x < startX + w; x++, i++) { + raster.setDataElements(x, y, cm.getDataElements(rgbArray[i], null)); + } + } + } + + /** + * Sets a the specified RGB value to the specified pixel of this + * BufferedImage. The pixel should be in the default RGB color model + * (TYPE_INT_ARGB) and default sRGB color space. + * + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param rgb + * the RGB value to be set. + */ + public synchronized void setRGB(int x, int y, int rgb) { + raster.setDataElements(x, y, cm.getDataElements(rgb, null)); + } + + public boolean isTileWritable(int tileX, int tileY) { + if (tileX == 0 && tileY == 0) { + return true; + } + // awt.226=Both tileX and tileY are not equal to 0 + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.226")); //$NON-NLS-1$ + } + + public void releaseWritableTile(int tileX, int tileY) { + } + + /** + * Gets a color in the TYPE_INT_ARGB color model and default sRGB color + * space of the specified pixel. + * + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @return the color of the specified pixel in the TYPE_INT_ARGB color model + * and default sRGB color space. + */ + public int getRGB(int x, int y) { + return cm.getRGB(raster.getDataElements(x, y, null)); + } + + /** + * Returns true if alpha is pre-multiplied, false if alpha is not + * pre-multiplied or there is no alpha. + * + * @return true if alpha is pre-multiplied, false if alpha is not + * pre-multiplied or there is no alpha. + */ + public boolean isAlphaPremultiplied() { + return cm.isAlphaPremultiplied(); + } + + public boolean hasTileWriters() { + return true; + } + + @Override + public void flush() { + imageSurf.dispose(); + } + + public int getWidth() { + return raster.getWidth(); + } + + /** + * Gets the image type. + * + * @return the image type. + */ public int getType() { - return TYPE_INT_ARGB; + return imageType; + } + + public int getTileWidth() { + return raster.getWidth(); + } + + public int getTileHeight() { + return raster.getHeight(); + } + + public int getTileGridYOffset() { + return raster.getSampleModelTranslateY(); + } + + public int getTileGridXOffset() { + return raster.getSampleModelTranslateX(); + } + + public int getNumYTiles() { + return 1; + } + + public int getNumXTiles() { + return 1; + } + + public int getMinY() { + return raster.getMinY(); + } + + public int getMinX() { + return raster.getMinX(); + } + + public int getMinTileY() { + return 0; + } + + public int getMinTileX() { + return 0; + } + + public int getHeight() { + return raster.getHeight(); + } + + /** + * Creates the image surface. + * + * @param type + * the type. + * @return the image surface. + */ + private ImageSurface createImageSurface(int type) { + return new ImageSurface(getColorModel(), getRaster(), type); + } + + /** + * Gets the image surface. + * + * @return the image surface. + */ + ImageSurface getImageSurface() { + return imageSurf; + } + + public int getTransparency() { + return cm.getTransparency(); } } - diff --git a/app/src/main/java/java/awt/image/BufferedImageFilter.java b/app/src/main/java/java/awt/image/BufferedImageFilter.java new file mode 100644 index 000000000..e9b95894f --- /dev/null +++ b/app/src/main/java/java/awt/image/BufferedImageFilter.java @@ -0,0 +1,397 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ + +package java.awt.image; + +import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The BufferedImageFilter class provides filtering operations to the + * BufferedImage objects using operators which implement BufferedImageOp + * interface. + * + * @since Android 1.0 + */ +public class BufferedImageFilter extends ImageFilter implements Cloneable { + + /** + * The Constant accessor. + */ + private static final AwtImageBackdoorAccessor accessor = AwtImageBackdoorAccessor.getInstance(); + + /** + * The op. + */ + private BufferedImageOp op; + + /** + * The raster. + */ + private WritableRaster raster; + + /** + * The i data. + */ + private int iData[]; + + /** + * The b data. + */ + private byte bData[]; + + /** + * The width. + */ + private int width; + + /** + * The height. + */ + private int height; + + /** + * The cm. + */ + private ColorModel cm; + + /** + * The forced rgb. + */ + private boolean forcedRGB = false; + + /** + * The transfer type. + */ + private int transferType = DataBuffer.TYPE_UNDEFINED; + + /** + * Instantiates a new BufferedImageFilter with the specified BufferedImageOp + * operator. + * + * @param op + * the specified BufferedImageOp operator. + * @throws NullPointerException + * if BufferedImageOp is null. + */ + public BufferedImageFilter(BufferedImageOp op) { + if (op == null) { + throw new NullPointerException(Messages.getString("awt.05")); //$NON-NLS-1$ + } + this.op = op; + } + + /** + * Gets the BufferedImageOp operator associated with this + * BufferedImageFilter object. + * + * @return the BufferedImageOp associated with this BufferedImageFilter + * object. + */ + public BufferedImageOp getBufferedImageOp() { + return op; + } + + @Override + public void setDimensions(int width, int height) { + this.width = width; + this.height = height; + // Stop image consuming if no pixels expected. + if (width <= 0 || height <= 0) { + consumer.imageComplete(ImageConsumer.STATICIMAGEDONE); + reset(); + } + } + + @Override + public void setColorModel(ColorModel model) { + if (this.cm != null && this.cm != model && raster != null) { + forceRGB(); + } else { + this.cm = model; + } + } + + @Override + public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, + int scansize) { + setPixels(x, y, w, h, model, pixels, off, scansize, true); + } + + @Override + public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off, + int scansize) { + setPixels(x, y, w, h, model, pixels, off, scansize, false); + } + + @Override + public void imageComplete(int status) { + if (status == STATICIMAGEDONE || status == SINGLEFRAMEDONE) { + BufferedImage bim = new BufferedImage(cm, raster, cm.isAlphaPremultiplied, null); + bim = op.filter(bim, null); + DataBuffer dstDb = bim.getRaster().getDataBuffer(); + ColorModel dstCm = bim.getColorModel(); + int dstW = bim.getWidth(); + int dstH = bim.getHeight(); + + consumer.setDimensions(dstW, dstH); + + if (dstDb.getDataType() == DataBuffer.TYPE_INT) { + consumer.setColorModel(dstCm); + consumer.setPixels(0, 0, dstW, dstH, dstCm, accessor.getDataInt(dstDb), 0, dstW); + } else if (dstDb.getDataType() == DataBuffer.TYPE_BYTE) { + consumer.setColorModel(dstCm); + consumer.setPixels(0, 0, dstW, dstH, dstCm, accessor.getDataByte(dstDb), 0, dstW); + } else { + int dstData[] = bim.getRGB(0, 0, dstW, dstH, null, 0, dstW); + dstCm = ColorModel.getRGBdefault(); + consumer.setColorModel(dstCm); + consumer.setPixels(0, 0, dstW, dstH, dstCm, dstData, 0, dstW); + } + } else if (status == IMAGEERROR || status == IMAGEABORTED) { + reset(); + } + + consumer.imageComplete(status); + } + + /** + * Sets the pixels. + * + * @param x + * the x. + * @param y + * the y. + * @param w + * the w. + * @param h + * the h. + * @param model + * the model. + * @param pixels + * the pixels. + * @param off + * the off. + * @param scansize + * the scansize. + * @param isByteData + * the is byte data. + */ + private void setPixels(int x, int y, int w, int h, ColorModel model, Object pixels, int off, + int scansize, boolean isByteData) { + // Check bounds + // Need to copy only the pixels that will fit into the destination area + if (x < 0) { + w -= x; + off += x; + x = 0; + } + + if (y < 0) { + h -= y; + off += y * scansize; + y = 0; + } + + if (x + w > width) { + w = width - x; + } + + if (y + h > height) { + h = height - y; + } + + if (w <= 0 || h <= 0) { + return; + } + + // Check model + if (this.cm == null) { + setColorModel(model); + } else if (model == null) { + model = this.cm; + } else if (!model.equals(this.cm)) { + forceRGB(); + } + + boolean canArraycopy; + // Process pixels + switch (transferType) { + case DataBuffer.TYPE_UNDEFINED: { + if (isByteData) { + transferType = DataBuffer.TYPE_BYTE; + createRaster(transferType); + // bData = new byte[width*height]; + canArraycopy = !forcedRGB; + break; + } + transferType = DataBuffer.TYPE_INT; + createRaster(transferType); + // iData = new int[width*height]; + canArraycopy = !forcedRGB || model.equals(ColorModel.getRGBdefault()); + break; + } // And proceed to copy the pixels + case DataBuffer.TYPE_INT: { + if (isByteData) { // There are int data already but the new data + // are bytes + forceRGB(); + canArraycopy = false; + break; + } else if (!forcedRGB || model.equals(ColorModel.getRGBdefault())) { + canArraycopy = true; + break; + } // Else fallback to the RGB conversion + } + case DataBuffer.TYPE_BYTE: { + if (isByteData && !forcedRGB) { + canArraycopy = true; + break; + } + + // RGB conversion + canArraycopy = false; + break; + } + default: { + throw new IllegalStateException(Messages.getString("awt.06")); //$NON-NLS-1$ + } + } + + off += x; + int maxOffset = off + h * scansize; + int dstOffset = x + y * width; + + if (canArraycopy) { + Object dstArray = isByteData ? (Object)bData : (Object)iData; + for (; off < maxOffset; off += scansize, dstOffset += width) { + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(pixels, off, dstArray, dstOffset, w); + } + } else { + // RGB conversion + for (; off < maxOffset; off += scansize, dstOffset += width) { + int srcPos = off; + int dstPos = dstOffset; + int maxDstPos = dstOffset + w; + for (; dstPos < maxDstPos; dstPos++, srcPos++) { + iData[dstPos] = model.getRGB(isByteData ? ((byte[])pixels)[srcPos] + : ((int[])pixels)[srcPos]); + } + } + } + } + + /** + * Force rgb. + */ + private void forceRGB() { + if (!forcedRGB) { + forcedRGB = true; + int size = width * height; + int rgbData[] = new int[size]; + + if (bData != null) { + for (int i = 0; i < size; i++) { + rgbData[i] = cm.getRGB(bData[i]); + } + } else if (iData != null) { + for (int i = 0; i < size; i++) { + rgbData[i] = cm.getRGB(iData[i]); + } + } + + cm = ColorModel.getRGBdefault(); + DataBufferInt db = new DataBufferInt(rgbData, size); + int masks[] = new int[] { + 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 + }; + raster = Raster.createPackedRaster(db, width, height, width, masks, null); + iData = accessor.getDataInt(db); + bData = null; + transferType = DataBuffer.TYPE_INT; + } + } + + /** + * Reset. + */ + private void reset() { + width = 0; + height = 0; + forcedRGB = false; + cm = null; + iData = null; + bData = null; + transferType = DataBuffer.TYPE_UNDEFINED; + raster = null; + } + + /** + * Creates the raster. + * + * @param dataType + * the data type. + */ + private void createRaster(int dataType) { + boolean createdValidBuffer = false; + try { + raster = cm.createCompatibleWritableRaster(width, height); + int rasterType = raster.getDataBuffer().getDataType(); + if (rasterType == dataType) { + switch (rasterType) { + case DataBuffer.TYPE_INT: { + iData = accessor.getDataInt(raster.getDataBuffer()); + if (iData != null) { + createdValidBuffer = true; + } + break; + } + case DataBuffer.TYPE_BYTE: { + bData = accessor.getDataByte(raster.getDataBuffer()); + if (bData != null) { + createdValidBuffer = true; + } + break; + } + default: + createdValidBuffer = false; + } + + if (cm == ColorModel.getRGBdefault()) { + forcedRGB = true; + } + } else { + createdValidBuffer = false; + } + } catch (Exception e) { + createdValidBuffer = false; + } + + if (createdValidBuffer == false) { + cm = ColorModel.getRGBdefault(); + raster = cm.createCompatibleWritableRaster(width, height); + iData = accessor.getDataInt(raster.getDataBuffer()); + bData = null; + forcedRGB = true; + } + } +} diff --git a/app/src/main/java/java/awt/image/BufferedImageOp.java b/app/src/main/java/java/awt/image/BufferedImageOp.java new file mode 100644 index 000000000..883a39d7e --- /dev/null +++ b/app/src/main/java/java/awt/image/BufferedImageOp.java @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey A. Petrenko + * @version $Revision$ + */ + +package java.awt.image; + +import java.awt.RenderingHints; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +/** + * The BufferedImageOp interface provides methods for performing transformations + * from source data to destination data for BufferedImage objects. An object + * implementing this interface can be passed into a BufferedImageFilter to + * operate on a BufferedImage. + * + * @since Android 1.0 + */ +public interface BufferedImageOp { + + /** + * Creates a destination image with the specified BufferedImage and + * ColorModel; this destination image is empty and has the correct size and + * number of bands. + * + * @param src + * the source BufferedImage. + * @param destCM + * the destination ColorModel. + * @return the BufferedImage. + */ + public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel destCM); + + /** + * Performs a filter operation on the source BufferedImage and stores the + * resulting BufferedImage to the destination BufferedImage. If the + * destination BufferedImage is null, a BufferedImage with an appropriate + * ColorModel is created. + * + * @param src + * the source BufferedImage. + * @param dest + * the destination BufferedImage, where the result is stored. + * @return the filtered BufferedImage. + */ + public BufferedImage filter(BufferedImage src, BufferedImage dest); + + /** + * Gets the bounds of filtered image. + * + * @param src + * the source BufferedImage to be filtered. + * @return the rectangle bounds of filtered image. + */ + public Rectangle2D getBounds2D(BufferedImage src); + + /** + * Gets the point of the destination image which corresponds to the + * specified point in the source image. + * + * @param srcPt + * the point of the source image. + * @param dstPt + * the point where the result will be stored. + * @return the destination point. + */ + public Point2D getPoint2D(Point2D srcPt, Point2D dstPt); + + /** + * Gets the RenderingHints of the BufferedImageOp. + * + * @return the RenderingHints of the BufferedImageOp. + */ + public RenderingHints getRenderingHints(); +} diff --git a/app/src/main/java/java/awt/image/ByteLookupTable.java b/app/src/main/java/java/awt/image/ByteLookupTable.java new file mode 100644 index 000000000..27cee30a1 --- /dev/null +++ b/app/src/main/java/java/awt/image/ByteLookupTable.java @@ -0,0 +1,140 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + * + * @date: Oct 14, 2005 + */ + +package java.awt.image; + +/** + * The ByteLookupTable class provides functionality for lookup operations, and + * is defined by an input byte array for bands or components of image and an + * offset value. The offset value will be subtracted from the input values + * before indexing the input arrays. The output of a lookup operation is + * represented as an array of unsigned bytes. + * + * @since Android 1.0 + */ +public class ByteLookupTable extends LookupTable { + + /** + * The data. + */ + private byte data[][]; + + /** + * Instantiates a new ByteLookupTable with the specified offset value and + * the specified byte array which represents the lookup table for all bands. + * + * @param offset + * the offset value. + * @param data + * the data array of bytes. + */ + public ByteLookupTable(int offset, byte[] data) { + super(offset, 1); + if (data.length < 1) + throw new IllegalArgumentException("Length of data should not be less then one"); + this.data = new byte[1][data.length]; + // The data array stored as a reference + this.data[0] = data; + } + + /** + * Instantiates a new ByteLookupTable with the specified offset value and + * the specified byte array of arrays which represents the lookup table for + * each band. + * + * @param offset + * the offset value. + * @param data + * the data array of bytes array for each band. + */ + public ByteLookupTable(int offset, byte[][] data) { + super(offset, data.length); + this.data = new byte[data.length][data[0].length]; + for (int i = 0; i < data.length; i++) { + // The data array for each band stored as a reference + this.data[i] = data[i]; + } + } + + /** + * Gets the lookup table of this ByteLookupTable object. If this + * ByteLookupTable object has one byte array for all bands, the returned + * array length is one. + * + * @return the lookup table of this ByteLookupTable object. + */ + public final byte[][] getTable() { + // Returns data by reference + return data; + } + + @Override + public int[] lookupPixel(int[] src, int[] dst) { + if (dst == null) { + dst = new int[src.length]; + } + + int offset = getOffset(); + if (getNumComponents() == 1) { + for (int i = 0; i < src.length; i++) { + dst[i] = data[0][src[i] - offset]; + } + } else { + for (int i = 0; i < getNumComponents(); i++) { + dst[i] = data[i][src[i] - offset]; + } + } + + return dst; + } + + /** + * Returns a byte array which contains samples of the specified pixel which + * is translated with the lookup table of this ByteLookupTable object. The + * resulted array is stored to the dst array. + * + * @param src + * the source array. + * @param dst + * the destination array where the result can be stored. + * @return the byte array of translated samples of a pixel. + */ + public byte[] lookupPixel(byte[] src, byte[] dst) { + if (dst == null) { + dst = new byte[src.length]; + } + + int offset = getOffset(); + if (getNumComponents() == 1) { + for (int i = 0; i < src.length; i++) { + dst[i] = data[0][src[i] - offset]; + } + } else { + for (int i = 0; i < getNumComponents(); i++) { + dst[i] = data[i][src[i] - offset]; + } + } + + return dst; + } +} diff --git a/app/src/main/java/java/awt/image/ColorConvertOp.java b/app/src/main/java/java/awt/image/ColorConvertOp.java new file mode 100644 index 000000000..1a1700b32 --- /dev/null +++ b/app/src/main/java/java/awt/image/ColorConvertOp.java @@ -0,0 +1,710 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ + +package java.awt.image; + +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.RenderingHints; +import java.awt.color.ColorSpace; +import java.awt.color.ICC_ColorSpace; +import java.awt.color.ICC_Profile; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.util.ArrayList; + +import org.apache.harmony.awt.gl.color.ColorConverter; +import org.apache.harmony.awt.gl.color.ColorScaler; +import org.apache.harmony.awt.gl.color.ICC_Transform; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The ColorConvertOp class converts the pixels of the data in the source image + * with the specified ColorSpace objects or an array of ICC_Profile objects. The + * result pixels are scaled to the precision of the destination image. + * + * @since Android 1.0 + */ +public class ColorConvertOp implements BufferedImageOp, RasterOp { + // Unused but required by interfaces + /** + * The rendering hints. + */ + RenderingHints renderingHints; + + // Sequence consisting of ColorSpace and ICC_Profile elements + /** + * The conversion sequence. + */ + Object conversionSequence[] = new ICC_Profile[0]; // To eliminate checks for + + // null + + // Not null if ColorConvertOp is constructed from the array of ICC profiles + /** + * The mid profiles. + */ + private ICC_Profile midProfiles[]; + + /** + * The cc. + */ + private final ColorConverter cc = new ColorConverter(); + + /** + * The t creator. + */ + private final ICC_TransfomCreator tCreator = new ICC_TransfomCreator(); + + /** + * The is icc. + */ + private boolean isICC = true; + + // Cached ICC_Transform + /** + * The Class ICC_TransfomCreator. + */ + private class ICC_TransfomCreator { + + /** + * The transform. + */ + private ICC_Transform transform; + + /** + * The max components. + */ + private int maxComponents; + + /** + * For the full ICC case. + * + * @param src + * the src. + * @param dst + * the dst. + * @param convSeq + * the conv seq. + * @return the transform. + */ + public ICC_Transform getTransform(ICC_Profile src, ICC_Profile dst, ICC_Profile convSeq[]) { + if (transform != null && src == transform.getSrc() && dst == transform.getDst()) { + return transform; + } + + int length = convSeq.length; + int srcFlg = 0, dstFlg = 0; + + if (length == 0 || src != convSeq[0]) { + if (src != null) { + srcFlg = 1; // need src profile + } + } + if (length == 0 || dst != convSeq[length - 1]) { + if (dst != null) { + dstFlg = 1; // need dst profile + } + } + + ICC_Profile profiles[]; + int nProfiles = length + srcFlg + dstFlg; + if (nProfiles == length) { + profiles = convSeq; + } else { + profiles = new ICC_Profile[nProfiles]; + int pos = 0; + if (srcFlg != 0) { + profiles[pos++] = src; + } + for (int i = 0; i < length; i++) { + profiles[pos++] = convSeq[i]; + } + if (dstFlg != 0) { + profiles[pos++] = dst; + } + } + + return transform = new ICC_Transform(profiles); + } + + /** + * Used only when there are non-ICC color spaces. Returns sequence of + * non-ICC color spaces and ICC transforms made from src, dst and + * conversionSequence. + * + * @param src + * the src. + * @param dst + * the dst. + * @return the sequence. + */ + public Object[] getSequence(Object src, Object dst) { + ArrayList profiles = new ArrayList(10); + ArrayList sequence = new ArrayList(10); + + // We need this profile anyway + ICC_Profile xyzProfile = ICC_Profile.getInstance(ColorSpace.CS_CIEXYZ); + + Object conversionFirst = null, conversionLast = null; + int conversionLength = conversionSequence.length; + if (conversionLength > 0) { + conversionFirst = conversionSequence[0]; + conversionLast = conversionSequence[conversionLength - 1]; + } + + boolean iccSequenceStarted = false; + + if (src != conversionFirst && src != null) { + if (src instanceof ICC_Profile) { + profiles.add(src); + iccSequenceStarted = true; + } else { + profiles.add(xyzProfile); + sequence.add(src); // Add non-ICC color space to the + // sequence + } + } else { + profiles.add(xyzProfile); + } + + for (int i = 0; i < conversionLength; i++) { + if (conversionSequence[i] instanceof ICC_Profile) { + profiles.add(conversionSequence[i]); + iccSequenceStarted = true; + } else if (iccSequenceStarted) { + profiles.add(xyzProfile); + + // Eliminate same profiles if there are any + // (e.g. xyzProfile may occur several times) + Object prev = profiles.get(0); + for (int k = 1; k < profiles.size(); k++) { + if (prev == profiles.get(k)) { + k--; + profiles.remove(k); + } + prev = profiles.get(k); + } + + // If only one profile left we skip the transform - + // it can be only CIEXYZ + if (profiles.size() > 1) { + sequence.add(new ICC_Transform(profiles.toArray(new ICC_Profile[0]))); + + // Add non-ICC color space to the sequence + sequence.add(conversionSequence[i]); + } + + profiles.clear(); + profiles.add(xyzProfile); + iccSequenceStarted = false; // Sequence of ICC profiles is + // processed + } else { // Add non-ICC color space to the sequence + sequence.add(conversionSequence[i]); + } + } + + if (dst != conversionLast && dst != null) { // Add last profile if + // needed + if (dst instanceof ICC_Profile) { + profiles.add(dst); + iccSequenceStarted = true; + } else if (iccSequenceStarted) { + profiles.add(xyzProfile); + } else { + sequence.add(dst); // Add last non-ICC color space to the + // sequence + } + } + + if (iccSequenceStarted) { // Make last transform if needed + sequence.add(new ICC_Transform(profiles.toArray(new ICC_Profile[0]))); + if (dst != null && !(dst instanceof ICC_Profile)) { + sequence.add(dst); // Add last non-ICC color space to the + // sequence + } + } + + // Calculate max number of components + // This number will be used for memory allocation + maxComponents = 0; + Object o; + for (int i = 0, size = sequence.size(); i < size; i++) { + o = sequence.get(i); + if (o instanceof ICC_Transform) { + ICC_Transform t = (ICC_Transform)o; + maxComponents = (maxComponents > t.getNumInputChannels() + 1) ? maxComponents + : t.getNumInputChannels() + 1; + maxComponents = (maxComponents > t.getNumOutputChannels() + 1) ? maxComponents + : t.getNumOutputChannels() + 1; + } else { + ColorSpace cs = (ColorSpace)o; + maxComponents = (maxComponents > cs.getNumComponents() + 1) ? maxComponents + : cs.getNumComponents() + 1; + } + } + + return sequence.toArray(); + } + } + + /** + * Instantiates a new ColorConvertOp object using two specified ColorSpace + * objects. + * + * @param srcCS + * the source ColorSpace. + * @param dstCS + * the destination ColorSpace. + * @param hints + * the RenderingHints object used for the color conversion, or + * null. + */ + public ColorConvertOp(ColorSpace srcCS, ColorSpace dstCS, RenderingHints hints) { + if (srcCS == null || dstCS == null) { + throw new NullPointerException(Messages.getString("awt.25B")); //$NON-NLS-1$ + } + + renderingHints = hints; + + boolean srcICC = srcCS instanceof ICC_ColorSpace; + boolean dstICC = dstCS instanceof ICC_ColorSpace; + + if (srcICC && dstICC) { + conversionSequence = new ICC_Profile[2]; + } else { + conversionSequence = new Object[2]; + isICC = false; + } + + if (srcICC) { + conversionSequence[0] = ((ICC_ColorSpace)srcCS).getProfile(); + } else { + conversionSequence[0] = srcCS; + } + + if (dstICC) { + conversionSequence[1] = ((ICC_ColorSpace)dstCS).getProfile(); + } else { + conversionSequence[1] = dstCS; + } + } + + /** + * Instantiates a new ColorConvertOp object from the specified ICC_Profile + * objects. + * + * @param profiles + * the array of ICC_Profile objects. + * @param hints + * the RenderingHints object used for the color conversion, or + * null. + */ + public ColorConvertOp(ICC_Profile profiles[], RenderingHints hints) { + if (profiles == null) { + throw new NullPointerException(Messages.getString("awt.25C")); //$NON-NLS-1$ + } + + renderingHints = hints; + + // This array is not used in the program logic, so don't need to copy it + // Store it only to return back + midProfiles = profiles; + + conversionSequence = new ICC_Profile[midProfiles.length]; + + // Add profiles to the conversion sequence + for (int i = 0, length = midProfiles.length; i < length; i++) { + conversionSequence[i] = midProfiles[i]; + } + } + + /** + * Instantiates a new ColorConvertOp object using the specified ColorSpace + * object. + * + * @param cs + * the destination ColorSpace or an intermediate ColorSpace. + * @param hints + * the RenderingHints object used for the color conversion, or + * null. + */ + public ColorConvertOp(ColorSpace cs, RenderingHints hints) { + if (cs == null) { + throw new NullPointerException(Messages.getString("awt.25B")); //$NON-NLS-1$ + } + + renderingHints = hints; + + if (cs instanceof ICC_ColorSpace) { + conversionSequence = new ICC_Profile[1]; + conversionSequence[0] = ((ICC_ColorSpace)cs).getProfile(); + } else { + conversionSequence = new Object[1]; + conversionSequence[0] = cs; + isICC = false; + } + } + + /** + * Instantiates a new ColorConvertOp object which converts from a source + * color space to a destination color space. + * + * @param hints + * the RenderingHints object used for the color conversion, or + * null. + */ + public ColorConvertOp(RenderingHints hints) { + renderingHints = hints; + } + + public final WritableRaster filter(Raster src, WritableRaster dst) { + if (conversionSequence.length < 2) { + throw new IllegalArgumentException(Messages.getString("awt.25D")); //$NON-NLS-1$ + } + + ICC_Profile srcPf = null, dstPf = null; // unused if isICC is false + int nSrcColorComps, nDstColorComps; + Object first = conversionSequence[0]; + Object last = conversionSequence[conversionSequence.length - 1]; + + // Get the number of input/output color components + if (isICC) { + srcPf = (ICC_Profile)first; + dstPf = (ICC_Profile)last; + nSrcColorComps = srcPf.getNumComponents(); + nDstColorComps = dstPf.getNumComponents(); + } else { + if (first instanceof ICC_Profile) { + srcPf = (ICC_Profile)first; + nSrcColorComps = srcPf.getNumComponents(); + } else { + nSrcColorComps = ((ColorSpace)first).getNumComponents(); + } + + if (last instanceof ICC_Profile) { + dstPf = (ICC_Profile)last; + nDstColorComps = dstPf.getNumComponents(); + } else { + nDstColorComps = ((ColorSpace)last).getNumComponents(); + } + } + + // Check that source and destination rasters are compatible with + // transforms and with each other + if (src.getNumBands() != nSrcColorComps) { + // awt.25E=Incorrect number of source raster bands. Should be equal + // to the number of color components of source colorspace. + throw new IllegalArgumentException(Messages.getString("awt.25E")); //$NON-NLS-1$ + } + + if (dst != null) { // Check destination raster + if (dst.getNumBands() != nDstColorComps) { + // awt.25F=Incorrect number of destination raster bands. Should + // be equal to the number of color components of destination + // colorspace. + throw new IllegalArgumentException(Messages.getString("awt.25F")); //$NON-NLS-1$ + } + + if (src.getWidth() != dst.getWidth() || src.getHeight() != dst.getHeight()) { + throw new IllegalArgumentException(Messages.getString("awt.260")); //$NON-NLS-1$ + } + + } else { + dst = createCompatibleDestRaster(src); + } + + if (isICC) { + // Create transform + ICC_Transform t = tCreator + .getTransform(srcPf, dstPf, (ICC_Profile[])conversionSequence); + cc.translateColor(t, src, dst); + } else { + Object[] sequence = tCreator.getSequence(null, null); + + // Get data from the source raster + ColorScaler scaler = new ColorScaler(); + scaler.loadScalingData(src, null); + float tmpData[][] = scaler.scaleNormalize(src); + + // Get source and destination color spaces + ColorSpace srcCS = (srcPf == null) ? (ColorSpace)first : new ICC_ColorSpace(srcPf); + ColorSpace dstCS = (dstPf == null) ? (ColorSpace)last : new ICC_ColorSpace(dstPf); + + applySequence(sequence, tmpData, srcCS, dstCS); + + scaler.loadScalingData(dst, null); + scaler.unscaleNormalized(dst, tmpData); + } + + return dst; + } + + public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel destCM) { + // If destination color model is passed only one line needed + if (destCM != null) { + return new BufferedImage(destCM, destCM.createCompatibleWritableRaster(src.getWidth(), + src.getHeight()), destCM.isAlphaPremultiplied(), null); + } + + int nSpaces = conversionSequence.length; + + if (nSpaces < 1) { + throw new IllegalArgumentException(Messages.getString("awt.261")); //$NON-NLS-1$ + } + + // Get destination color space + Object destination = conversionSequence[nSpaces - 1]; + ColorSpace dstCS = (destination instanceof ColorSpace) ? (ColorSpace)destination + : new ICC_ColorSpace((ICC_Profile)destination); + + ColorModel srcCM = src.getColorModel(); + ColorModel dstCM = new ComponentColorModel(dstCS, srcCM.hasAlpha(), srcCM + .isAlphaPremultiplied(), srcCM.getTransparency(), srcCM.getTransferType()); + + return new BufferedImage(dstCM, destCM.createCompatibleWritableRaster(src.getWidth(), src + .getHeight()), destCM.isAlphaPremultiplied(), null); + } + + public final BufferedImage filter(BufferedImage src, BufferedImage dst) { + if (dst == null && conversionSequence.length < 1) { + throw new IllegalArgumentException(Messages.getString("awt.262")); //$NON-NLS-1$ + } + + ColorModel srcCM = src.getColorModel(); + // First handle index color model + if (srcCM instanceof IndexColorModel) { + src = ((IndexColorModel)srcCM).convertToIntDiscrete(src.getRaster(), false); + } + ColorSpace srcCS = srcCM.getColorSpace(); + + BufferedImage res; + boolean isDstIndex = false; + if (dst != null) { + + if (src.getWidth() != dst.getWidth() || src.getHeight() != dst.getHeight()) { + throw new IllegalArgumentException(Messages.getString("awt.263")); //$NON-NLS-1$ + } + + if (dst.getColorModel() instanceof IndexColorModel) { + isDstIndex = true; + res = createCompatibleDestImage(src, null); + } else { + res = dst; + } + } else { + res = createCompatibleDestImage(src, null); + } + ColorModel dstCM = res.getColorModel(); + ColorSpace dstCS = dstCM.getColorSpace(); + + ICC_Profile srcPf = null, dstPf = null; + if (srcCS instanceof ICC_ColorSpace) { + srcPf = ((ICC_ColorSpace)srcCS).getProfile(); + } + if (dstCS instanceof ICC_ColorSpace) { + dstPf = ((ICC_ColorSpace)dstCS).getProfile(); + } + + boolean isFullICC = isICC && srcPf != null && dstPf != null; + + if (isFullICC) { + ICC_Transform t = tCreator + .getTransform(srcPf, dstPf, (ICC_Profile[])conversionSequence); + cc.translateColor(t, src, res); + } else { // Perform non-ICC transform + Object sequence[] = tCreator.getSequence(srcPf == null ? (Object)srcCS : srcPf, + dstPf == null ? (Object)dstCS : dstPf); + + int srcW = src.getWidth(); + int srcH = src.getHeight(); + int numPixels = srcW * srcH; + + // Load all pixel data into array tmpData + float tmpData[][] = new float[numPixels][tCreator.maxComponents]; + for (int row = 0, dataPos = 0; row < srcW; row++) { + for (int col = 0; col < srcH; col++) { + tmpData[dataPos] = srcCM.getNormalizedComponents(src.getRaster() + .getDataElements(row, col, null), tmpData[dataPos], 0); + dataPos++; + } + } + + // Copy alpha channel if needed + float alpha[] = null; + int alphaIdx = srcCM.numComponents - 1; + if (srcCM.hasAlpha() && dstCM.hasAlpha()) { + alpha = new float[numPixels]; + for (int i = 0; i < numPixels; i++) { + alpha[i] = tmpData[i][alphaIdx]; + } + } + + // Translate colors + applySequence(sequence, tmpData, srcCS, dstCS); + + // Copy alpha if needed + if (dstCM.hasAlpha()) { + alphaIdx = dstCM.numComponents - 1; + if (alpha != null) { + for (int i = 0; i < numPixels; i++) { + tmpData[i][alphaIdx] = alpha[i]; + } + } else { + for (int i = 0; i < numPixels; i++) { + tmpData[i][alphaIdx] = 1f; + } + } + } + + // Store data back to the image + for (int row = 0, dataPos = 0; row < srcW; row++) { + for (int col = 0; col < srcH; col++) { + res.getRaster().setDataElements(row, col, + dstCM.getDataElements(tmpData[dataPos++], 0, null)); + } + } + } + + if (isDstIndex) { // Convert image into indexed color + Graphics2D g2d = dst.createGraphics(); + g2d.drawImage(res, 0, 0, null); + g2d.dispose(); + return dst; + } + + return res; + } + + /** + * Apply sequence. + * + * @param sequence + * the sequence. + * @param tmpData + * the tmp data. + * @param srcCS + * the src cs. + * @param dstCS + * the dst cs. + */ + private void applySequence(Object sequence[], float tmpData[][], ColorSpace srcCS, + ColorSpace dstCS) { + ColorSpace xyzCS = ColorSpace.getInstance(ColorSpace.CS_CIEXYZ); + + int numPixels = tmpData.length; + + // First transform... + if (sequence[0] instanceof ICC_Transform) { // ICC + ICC_Transform t = (ICC_Transform)sequence[0]; + cc.translateColor(t, tmpData, srcCS, xyzCS, numPixels); + } else { // non ICC + for (int k = 0; k < numPixels; k++) { + tmpData[k] = srcCS.toCIEXYZ(tmpData[k]); + } + cc.loadScalingData(xyzCS); // prepare for scaling XYZ + } + + for (Object element : sequence) { + if (element instanceof ICC_Transform) { + ICC_Transform t = (ICC_Transform)element; + cc.translateColor(t, tmpData, null, null, numPixels); + } else { + ColorSpace cs = (ColorSpace)element; + for (int k = 0; k < numPixels; k++) { + tmpData[k] = cs.fromCIEXYZ(tmpData[k]); + tmpData[k] = cs.toCIEXYZ(tmpData[k]); + } + } + } + + // Last transform... + if (sequence[sequence.length - 1] instanceof ICC_Transform) { // ICC + ICC_Transform t = (ICC_Transform)sequence[sequence.length - 1]; + cc.translateColor(t, tmpData, xyzCS, dstCS, numPixels); + } else { // non ICC + for (int k = 0; k < numPixels; k++) { + tmpData[k] = dstCS.fromCIEXYZ(tmpData[k]); + } + } + } + + public final Point2D getPoint2D(Point2D srcPt, Point2D dstPt) { + if (dstPt != null) { + dstPt.setLocation(srcPt); + return dstPt; + } + return new Point2D.Float((float)srcPt.getX(), (float)srcPt.getY()); + } + + public WritableRaster createCompatibleDestRaster(Raster src) { + int nComps = 0; + int nSpaces = conversionSequence.length; + + if (nSpaces < 2) { + throw new IllegalArgumentException(Messages.getString("awt.261")); //$NON-NLS-1$ + } + + Object lastCS = conversionSequence[nSpaces - 1]; + if (lastCS instanceof ColorSpace) { + nComps = ((ColorSpace)lastCS).getNumComponents(); + } else { + nComps = ((ICC_Profile)lastCS).getNumComponents(); + } + + // Calculate correct data type + int dstDataType = src.getDataBuffer().getDataType(); + if (dstDataType != DataBuffer.TYPE_BYTE && dstDataType != DataBuffer.TYPE_SHORT) { + dstDataType = DataBuffer.TYPE_SHORT; + } + + return Raster.createInterleavedRaster(dstDataType, src.getWidth(), src.getHeight(), nComps, + new Point(src.getMinX(), src.getMinY())); + } + + public final Rectangle2D getBounds2D(Raster src) { + return src.getBounds(); + } + + public final Rectangle2D getBounds2D(BufferedImage src) { + return src.getRaster().getBounds(); + } + + /** + * Gets an array of ICC_Profiles objects which constructs this + * ColorConvertOp object or returns null if this ColorConvertOp is not + * constructed from array of ICC_Profiles. + * + * @return an array of ICC_Profiles objects which constructs this + * ColorConvertOp object or returns null if this ColorConvertOp is + * not constructed from array of ICC_Profiles. + */ + public final ICC_Profile[] getICC_Profiles() { + if (midProfiles != null) { + return midProfiles; + } + return null; + } + + public final RenderingHints getRenderingHints() { + return renderingHints; + } +} diff --git a/app/src/main/java/java/awt/image/ColorModel.java b/app/src/main/java/java/awt/image/ColorModel.java new file mode 100644 index 000000000..1b084e121 --- /dev/null +++ b/app/src/main/java/java/awt/image/ColorModel.java @@ -0,0 +1,964 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.awt.Transparency; +import java.awt.color.ColorSpace; +import java.util.Arrays; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The class ColorModel. + * + * @since Android 1.0 + */ +public abstract class ColorModel implements Transparency { + + /** + * The pixel_bits. + */ + protected int pixel_bits; // Pixel length in bits + + /** + * The transfer type. + */ + protected int transferType; + + /** + * The cs. + */ + ColorSpace cs; + + /** + * The has alpha. + */ + boolean hasAlpha; + + /** + * The is alpha premultiplied. + */ + boolean isAlphaPremultiplied; + + /** + * The transparency. + */ + int transparency; + + /** + * The num color components. + */ + int numColorComponents; + + /** + * The num components. + */ + int numComponents; + + /** + * The bits. + */ + int[] bits; // Array of components masks + + /** + * The max values. + */ + int[] maxValues = null; // Max values that may be represent by color + + // components + + /** + * The max bit length. + */ + int maxBitLength; // Max length color components in bits + + /** + * The RG bdefault. + */ + private static ColorModel RGBdefault; + + /** + * Instantiates a new color model with the specified values. + * + * @param pixel_bits + * the pixel length in bits. + * @param bits + * the array of component masks. + * @param cspace + * the color space. + * @param hasAlpha + * whether the color model has alpha. + * @param isAlphaPremultiplied + * whether the alpha is pre-multiplied. + * @param transparency + * the transparency strategy, @see java.awt.Transparency. + * @param transferType + * the transfer type (primitive java type to use for the + * components). + */ + protected ColorModel(int pixel_bits, int[] bits, ColorSpace cspace, boolean hasAlpha, + boolean isAlphaPremultiplied, int transparency, int transferType) { + + if (pixel_bits < 1) { + // awt.26B=The number of bits in the pixel values is less than 1 + throw new IllegalArgumentException(Messages.getString("awt.26B")); //$NON-NLS-1$ + } + + if (bits == null) { + // awt.26C=bits is null + throw new NullPointerException(Messages.getString("awt.26C")); //$NON-NLS-1$ + } + + int sum = 0; + for (int element : bits) { + if (element < 0) { + // awt.26D=The elements in bits is less than 0 + throw new IllegalArgumentException(Messages.getString("awt.26D")); //$NON-NLS-1$ + } + sum += element; + } + + if (sum < 1) { + // awt.26E=The sum of the number of bits in bits is less than 1 + throw new NullPointerException(Messages.getString("awt.26E")); //$NON-NLS-1$ + } + + if (cspace == null) { + // awt.26F=The cspace is null + throw new IllegalArgumentException(Messages.getString("awt.26F")); //$NON-NLS-1$ + } + + if (transparency < Transparency.OPAQUE || transparency > Transparency.TRANSLUCENT) { + // awt.270=The transparency is not a valid value + throw new IllegalArgumentException(Messages.getString("awt.270")); //$NON-NLS-1$ + } + + this.pixel_bits = pixel_bits; + this.bits = bits.clone(); + + maxValues = new int[bits.length]; + maxBitLength = 0; + for (int i = 0; i < maxValues.length; i++) { + maxValues[i] = (1 << bits[i]) - 1; + if (bits[i] > maxBitLength) { + maxBitLength = bits[i]; + } + } + + cs = cspace; + this.hasAlpha = hasAlpha; + this.isAlphaPremultiplied = isAlphaPremultiplied; + numColorComponents = cs.getNumComponents(); + + if (hasAlpha) { + numComponents = numColorComponents + 1; + } else { + numComponents = numColorComponents; + } + + this.transparency = transparency; + this.transferType = transferType; + + } + + /** + * Instantiates a new color model with the specified pixel bit depth. The + * transferType is chosen based on the pixel bits, and the other data fields + * are given default values. + * + * @param bits + * the array of component masks. + */ + public ColorModel(int bits) { + + if (bits < 1) { + // awt.271=The number of bits in bits is less than 1 + throw new IllegalArgumentException(Messages.getString("awt.271")); //$NON-NLS-1$ + } + + pixel_bits = bits; + transferType = getTransferType(bits); + cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); + hasAlpha = true; + isAlphaPremultiplied = false; + transparency = Transparency.TRANSLUCENT; + + numColorComponents = 3; + numComponents = 4; + + this.bits = null; + } + + /** + * Gets the data elements from the specified component array, transforming + * them according to rules of the color model. + * + * @param components + * the components. + * @param offset + * the offset in the normComponents array. + * @param obj + * the array that the result is written to: an array of values + * whose length must be the number of components used by the + * color model and whose type depends on the transfer type (based + * on the pixel bit depth), or null to have the appropriate array + * created. + * @return the array of data elements. + */ + public Object getDataElements(int[] components, int offset, Object obj) { + throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ + "supported by this ColorModel"); //$NON-NLS-1$ + } + + /** + * Gets the data elements from the specified array of normalized components. + * + * @param normComponents + * the array normalized components. + * @param normOffset + * the offset in the normComponents array. + * @param obj + * the array that the result is written to: an array of values + * whose length must be the number of components used by the + * color model and whose type depends on the transfer type (based + * on the pixel bit depth), or null to have the appropriate array + * created. + * @return the array of data elements. + */ + public Object getDataElements(float[] normComponents, int normOffset, Object obj) { + int unnormComponents[] = getUnnormalizedComponents(normComponents, normOffset, null, 0); + return getDataElements(unnormComponents, 0, obj); + } + + /** + * Gets the data elements corresponding to the pixel determined by the RGB + * data. + * + * @param rgb + * the RGB integer value that defines the pixel. + * @param pixel + * the array that the result is written to: an array of values + * whose length must be the number of components used by the + * color model and whose type depends on the transfer type (based + * on the pixel bit depth), or null to have the appropriate array + * created. + * @return the array of data elements. + */ + public Object getDataElements(int rgb, Object pixel) { + throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ + "supported by this ColorModel"); //$NON-NLS-1$ + } + + /** + * Gets the child raster corresponding to the alpha channel of the specified + * writable raster, or null if alpha is not supported. + * + * @param raster + * the raster. + * @return the alpha raster. + */ + public WritableRaster getAlphaRaster(WritableRaster raster) { + return null; + } + + /** + * Creates a new color model by coercing the data in the writable raster in + * accordance with the alpha strategy of this color model. + * + * @param raster + * the raster. + * @param isAlphaPremultiplied + * whether the alpha is pre-multiplied in this color model + * @return the new color model. + */ + public ColorModel coerceData(WritableRaster raster, boolean isAlphaPremultiplied) { + throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ + "supported by this ColorModel"); //$NON-NLS-1$ + } + + @Override + public String toString() { + // The output format based on 1.5 release behavior. + // It could be reveled such way: + // ColorModel cm = new + // ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB, + // false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE); + // System.out.println(cm.toString()); + return "ColorModel: Color Space = " + cs.toString() + "; has alpha = " //$NON-NLS-1$ //$NON-NLS-2$ + + hasAlpha + "; is alpha premultipied = " //$NON-NLS-1$ + + isAlphaPremultiplied + "; transparency = " + transparency //$NON-NLS-1$ + + "; number color components = " + numColorComponents //$NON-NLS-1$ + + "; pixel bits = " + pixel_bits + "; transfer type = " //$NON-NLS-1$ //$NON-NLS-2$ + + transferType; + } + + /** + * Gets the components of the pixel determined by the data array. + * + * @param pixel + * the data array that defines the pixel (whose primitive type + * corresponds to the pixel length in bits. + * @see ColorModel#getTransferType() + * @param components + * the the array where the resulting components are written (or + * null to prompt the method to create the return array). + * @param offset + * the offset that tells where the results should be written in + * the return array. + * @return the array of components. + */ + public int[] getComponents(Object pixel, int[] components, int offset) { + throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ + "supported by this ColorModel"); //$NON-NLS-1$ + } + + /** + * Gets the normalized components of the pixel determined by the data array. + * + * @param pixel + * the data array that defines the pixel (whose primitive type + * corresponds to the pixel length in bits. + * @see ColorModel#getTransferType() + * @param normComponents + * the array where the resulting normalized components are + * written (or null to prompt the method to create the return + * array). + * @param normOffset + * the offset that tells where the results should be written in + * the return array. + * @return the array of normalized components. + */ + public float[] getNormalizedComponents(Object pixel, float[] normComponents, int normOffset) { + + if (pixel == null) { + // awt.294=pixel is null + throw new NullPointerException(Messages.getString("awt.294")); //$NON-NLS-1$ + } + + int unnormComponents[] = getComponents(pixel, null, 0); + return getNormalizedComponents(unnormComponents, 0, normComponents, normOffset); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ColorModel)) { + return false; + } + ColorModel cm = (ColorModel)obj; + + return (pixel_bits == cm.getPixelSize() && transferType == cm.getTransferType() + && cs.getType() == cm.getColorSpace().getType() && hasAlpha == cm.hasAlpha() + && isAlphaPremultiplied == cm.isAlphaPremultiplied() + && transparency == cm.getTransparency() + && numColorComponents == cm.getNumColorComponents() + && numComponents == cm.getNumComponents() && Arrays.equals(bits, cm + .getComponentSize())); + } + + /** + * Gets the red component of the pixel determined by the data array. + * + * @param inData + * the data array that defines the pixel (whose primitive type + * corresponds to the pixel length in bits. + * @see ColorModel#getTransferType() + * @return the red. + */ + public int getRed(Object inData) { + return getRed(constructPixel(inData)); + } + + /** + * Gets the RGB integer value corresponding to the pixel defined by the data + * array. + * + * @param inData + * the data array that defines the pixel (whose primitive type + * corresponds to the pixel length in bits. + * @see ColorModel#getTransferType() + * @return the integer value that gives the pixel's colors in RGB format. + */ + public int getRGB(Object inData) { + return (getAlpha(inData) << 24 | getRed(inData) << 16 | getGreen(inData) << 8 | getBlue(inData)); + } + + /** + * Gets the green component of the pixel defined by the data array. + * + * @param inData + * the data array that defines the pixel (whose primitive type + * corresponds to the pixel length in bits. + * @see ColorModel#getTransferType() + * @return the green. + */ + public int getGreen(Object inData) { + return getGreen(constructPixel(inData)); + } + + /** + * Gets the blue component of the pixel defined by the data array. + * + * @param inData + * the data array that defines the pixel (whose primitive type + * corresponds to the pixel length in bits. + * @see ColorModel#getTransferType() + * @return the blue. + */ + public int getBlue(Object inData) { + return getBlue(constructPixel(inData)); + } + + /** + * Gets the alpha component of the pixel defined by the data array. + * + * @param inData + * the data array that defines the pixel (whose primitive type + * corresponds to the pixel length in bits. + * @see ColorModel#getTransferType() + * @return the alpha. + */ + public int getAlpha(Object inData) { + return getAlpha(constructPixel(inData)); + } + + /** + * Creates a compatible writable raster. + * + * @param w + * the width of the desired writable raster. + * @param h + * the height of the desired writable raster. + * @return the writable raster. + */ + public WritableRaster createCompatibleWritableRaster(int w, int h) { + throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ + "supported by this ColorModel"); //$NON-NLS-1$ + } + + /** + * Checks if the sample model is compatible with this color model. + * + * @param sm + * the sample model. + * @return true, if the sample model is compatible with this color model. + */ + public boolean isCompatibleSampleModel(SampleModel sm) { + throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ + "supported by this ColorModel"); //$NON-NLS-1$ + } + + /** + * Creates the compatible sample model. + * + * @param w + * the width of the desired sample model. + * @param h + * the height of the desired sample model. + * @return the sample model. + */ + public SampleModel createCompatibleSampleModel(int w, int h) { + throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ + "supported by this ColorModel"); //$NON-NLS-1$ + } + + /** + * Checks if the specified raster is compatible with this color model. + * + * @param raster + * the raster to inspect. + * @return true, if the raster is compatible with this color model. + */ + public boolean isCompatibleRaster(Raster raster) { + throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ + "supported by this ColorModel"); //$NON-NLS-1$ + } + + /** + * Gets the color space of this color model. + * + * @return the color space. + */ + public final ColorSpace getColorSpace() { + return cs; + } + + /** + * Gets the normalized components corresponding to the specified + * unnormalized components. + * + * @param components + * the array of unnormalized components. + * @param offset + * the offset where the components should be read from the array + * of unnormalized components. + * @param normComponents + * the array where the resulting normalized components are + * written (or null to prompt the method to create the return + * array). + * @param normOffset + * the offset that tells where the results should be written in + * the return array. + * @return the normalized components. + */ + public float[] getNormalizedComponents(int[] components, int offset, float normComponents[], + int normOffset) { + if (bits == null) { + // awt.26C=bits is null + throw new UnsupportedOperationException(Messages.getString("awt.26C")); //$NON-NLS-1$ + } + + if (normComponents == null) { + normComponents = new float[numComponents + normOffset]; + } + + if (hasAlpha && isAlphaPremultiplied) { + float normAlpha = (float)components[offset + numColorComponents] + / maxValues[numColorComponents]; + if (normAlpha != 0.0f) { + for (int i = 0; i < numColorComponents; i++) { + normComponents[normOffset + i] = components[offset + i] + / (normAlpha * maxValues[i]); + } + normComponents[normOffset + numColorComponents] = normAlpha; + } else { + for (int i = 0; i < numComponents; i++) { + normComponents[normOffset + i] = 0.0f; + } + } + } else { + for (int i = 0; i < numComponents; i++) { + normComponents[normOffset + i] = (float)components[offset + i] / maxValues[i]; + } + } + + return normComponents; + } + + /** + * Gets the data element corresponding to the unnormalized components. + * + * @param components + * the components. + * @param offset + * the offset to start reading the components from the array of + * components. + * @return the data element. + */ + public int getDataElement(int[] components, int offset) { + throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ + "supported by this ColorModel"); //$NON-NLS-1$ + } + + /** + * Gets the unnormalized components corresponding to the specified + * normalized components. + * + * @param normComponents + * the array of normalized components. + * @param normOffset + * the offset where the components should be read from the array + * of normalized components. + * @param components + * the array where the resulting unnormalized components are + * written (or null to prompt the method to create the return + * array). + * @param offset + * the offset that tells where the results should be written in + * the return array. + * @return the unnormalized components. + */ + public int[] getUnnormalizedComponents(float normComponents[], int normOffset, + int components[], int offset) { + + if (bits == null) { + // awt.26C=bits is null + throw new UnsupportedOperationException(Messages.getString("awt.26C")); //$NON-NLS-1$ + } + + if (normComponents.length - normOffset < numComponents) { + // awt.273=The length of normComponents minus normOffset is less + // than numComponents + throw new IllegalArgumentException(Messages.getString("awt.273")); //$NON-NLS-1$ + } + + if (components == null) { + components = new int[numComponents + offset]; + } else { + if (components.length - offset < numComponents) { + // awt.272=The length of components minus offset is less than + // numComponents + throw new IllegalArgumentException(Messages.getString("awt.272")); //$NON-NLS-1$ + } + } + + if (hasAlpha && isAlphaPremultiplied) { + float alpha = normComponents[normOffset + numColorComponents]; + for (int i = 0; i < numColorComponents; i++) { + components[offset + i] = (int)(normComponents[normOffset + i] * maxValues[i] + * alpha + 0.5f); + } + components[offset + numColorComponents] = (int)(normComponents[normOffset + + numColorComponents] + * maxValues[numColorComponents] + 0.5f); + } else { + for (int i = 0; i < numComponents; i++) { + components[offset + i] = (int)(normComponents[normOffset + i] * maxValues[i] + 0.5f); + } + } + + return components; + } + + /** + * Gets the data element corresponding to the normalized components. + * + * @param normComponents + * the normalized components. + * @param normOffset + * the offset where the normalized components should be read from + * the normalized component array. + * @return the data element. + */ + public int getDataElement(float normComponents[], int normOffset) { + int unnormComponents[] = getUnnormalizedComponents(normComponents, normOffset, null, 0); + return getDataElement(unnormComponents, 0); + } + + /** + * Takes a pixel whose data is defined by an integer, and writes the + * corresponding components into the components array, starting from the + * index offset. + * + * @param pixel + * the pixel data. + * @param components + * the data array to write the components to (or null to have the + * method create the return array). + * @param offset + * the offset that determines where the results are written in + * the components array. + * @return the array of components corresponding to the pixel. + */ + public int[] getComponents(int pixel, int components[], int offset) { + throw new UnsupportedOperationException("This method is not " + //$NON-NLS-1$ + "supported by this ColorModel"); //$NON-NLS-1$ + } + + /** + * Gets the red component of the pixel determined by the pixel data. + * + * @param pixel + * the pixel. + * @return the red component of the given pixel. + */ + public abstract int getRed(int pixel); + + /** + * Takes the pixel data and returns the integer value corresponding to the + * pixel's color in RGB format. + * + * @param pixel + * the pixel data. + * @return the corresponding RGB integer value. + */ + public int getRGB(int pixel) { + return (getAlpha(pixel) << 24 | getRed(pixel) << 16 | getGreen(pixel) << 8 | getBlue(pixel)); + } + + /** + * Gets the green component of the pixel determined by the pixel data. + * + * @param pixel + * the pixel. + * @return the green component of the given pixel. + */ + public abstract int getGreen(int pixel); + + /** + * Gets the size of the desired component of this color model. + * + * @param componentIdx + * the index that determines which component size to get. + * @return the component size corresponding to the index. + * @throws NullPointerException + * if this color model doesn't support an array of separate + * components. + * @throws ArrayIndexOutOfBoundsException + * if the index is negative or greater than or equal to the + * number of components. + */ + public int getComponentSize(int componentIdx) { + if (bits == null) { + // awt.26C=bits is null + throw new NullPointerException(Messages.getString("awt.26C")); //$NON-NLS-1$ + } + + if (componentIdx < 0 || componentIdx >= bits.length) { + // awt.274=componentIdx is greater than the number of components or + // less than zero + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.274")); //$NON-NLS-1$ + } + + return bits[componentIdx]; + } + + /** + * Gets the blue component of the pixel determined by the pixel data. + * + * @param pixel + * the pixel. + * @return the blue component of the given pixel. + */ + public abstract int getBlue(int pixel); + + /** + * Gets the alpha component of the pixel determined by the pixel data. + * + * @param pixel + * the pixel. + * @return the alpha component of the given pixel. + */ + public abstract int getAlpha(int pixel); + + /** + * Gets the array of sizes of the different components. + * + * @return the array of sizes of the different components. + */ + public int[] getComponentSize() { + if (bits != null) { + return bits.clone(); + } + return null; + } + + /** + * Checks if the alpha component is pre-multiplied. + * + * @return true, if the alpha component is pre-multiplied. + */ + public final boolean isAlphaPremultiplied() { + return isAlphaPremultiplied; + } + + /** + * Checks whether this color model supports alpha. + * + * @return true, if this color model has alpha. + */ + public final boolean hasAlpha() { + return hasAlpha; + } + + @Override + public int hashCode() { + int hash = 0; + int tmp; + + if (hasAlpha) { + hash ^= 1; + hash <<= 8; + } + if (isAlphaPremultiplied) { + hash ^= 1; + hash <<= 8; + } + + tmp = hash >>> 24; + hash ^= numColorComponents; + hash <<= 8; + hash |= tmp; + + tmp = hash >>> 24; + hash ^= transparency; + hash <<= 8; + hash |= tmp; + + tmp = hash >>> 24; + hash ^= cs.getType(); + hash <<= 8; + hash |= tmp; + + tmp = hash >>> 24; + hash ^= pixel_bits; + hash <<= 8; + hash |= tmp; + + tmp = hash >>> 24; + hash ^= transferType; + hash <<= 8; + hash |= tmp; + + if (bits != null) { + + for (int element : bits) { + tmp = hash >>> 24; + hash ^= element; + hash <<= 8; + hash |= tmp; + } + + } + + return hash; + } + + public int getTransparency() { + return transparency; + } + + /** + * Gets the transfer type, which is the type of Java primitive value that + * corresponds to the bit length per pixel: either + * {@link DataBuffer#TYPE_BYTE}, {@link DataBuffer#TYPE_USHORT}, + * {@link DataBuffer#TYPE_INT}, or {@link DataBuffer#TYPE_UNDEFINED}. + * + * @return the transfer type. + */ + public final int getTransferType() { + return transferType; + } + + /** + * Gets the pixel size in bits. + * + * @return the pixel size. + */ + public int getPixelSize() { + return pixel_bits; + } + + /** + * Gets the number of components of this color model. + * + * @return the number of components. + */ + public int getNumComponents() { + return numComponents; + } + + /** + * Gets the number of color components of this color model. + * + * @return the number color components. + */ + public int getNumColorComponents() { + return numColorComponents; + } + + /** + * Gets the default RGB color model. + * + * @return the default RGB color model. + */ + public static ColorModel getRGBdefault() { + if (RGBdefault == null) { + RGBdefault = new DirectColorModel(32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000); + } + return RGBdefault; + } + + /* + * Construct INT pixel representation from Object + * @param obj + * @return + */ + /** + * Construct pixel. + * + * @param obj + * the obj. + * @return the int. + */ + private int constructPixel(Object obj) { + int pixel = 0; + + switch (getTransferType()) { + + case DataBuffer.TYPE_BYTE: + byte[] bPixel = (byte[])obj; + if (bPixel.length > 1) { + // awt.275=This pixel representation is not suuported by tis + // Color Model + throw new UnsupportedOperationException(Messages.getString("awt.275")); //$NON-NLS-1$ + } + pixel = bPixel[0] & 0xff; + break; + + case DataBuffer.TYPE_USHORT: + short[] sPixel = (short[])obj; + if (sPixel.length > 1) { + // awt.275=This pixel representation is not suuported by tis + // Color Model + throw new UnsupportedOperationException(Messages.getString("awt.275")); //$NON-NLS-1$ + } + pixel = sPixel[0] & 0xffff; + break; + + case DataBuffer.TYPE_INT: + int[] iPixel = (int[])obj; + if (iPixel.length > 1) { + // awt.275=This pixel representation is not suuported by tis + // Color Model + throw new UnsupportedOperationException(Messages.getString("awt.275")); //$NON-NLS-1$ + } + pixel = iPixel[0]; + break; + + default: + // awt.22D=This transferType ( {0} ) is not supported by this + // color model + throw new UnsupportedOperationException(Messages.getString("awt.22D", //$NON-NLS-1$ + transferType)); + + } + return pixel; + } + + /** + * Gets the transfer type, which is the type of Java primitive value that + * corresponds to the bit length per pixel: either + * {@link DataBuffer#TYPE_BYTE}, {@link DataBuffer#TYPE_USHORT}, + * {@link DataBuffer#TYPE_INT}, or {@link DataBuffer#TYPE_UNDEFINED}. + * + * @param bits + * the array of component masks. + * @return the transfer type. + */ + static int getTransferType(int bits) { + if (bits <= 8) { + return DataBuffer.TYPE_BYTE; + } else if (bits <= 16) { + return DataBuffer.TYPE_USHORT; + } else if (bits <= 32) { + return DataBuffer.TYPE_INT; + } else { + return DataBuffer.TYPE_UNDEFINED; + } + } + + @Override + public void finalize() { + // This method is added for the API compatibility + // Don't need to call super since Object's finalize is always empty + } +} diff --git a/app/src/main/java/java/awt/image/ComponentColorModel.java b/app/src/main/java/java/awt/image/ComponentColorModel.java new file mode 100644 index 000000000..4328fd37e --- /dev/null +++ b/app/src/main/java/java/awt/image/ComponentColorModel.java @@ -0,0 +1,1482 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.awt.color.ColorSpace; + +import org.apache.harmony.awt.gl.color.LUTColorConverter; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Class ComponentColorModel represents a color model that is defined in + * terms of its components. + * + * @since Android 1.0 + */ +public class ComponentColorModel extends ColorModel { + + /** + * The signed. + */ + private boolean signed; // Pixel samples are signed. + + // Samples with TransferType DataBuffer.TYPE_BYTE, + // DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT - + // unsigned. Samples with others TransferType - + // signed. + + /** + * The integral. + */ + private boolean integral; // Pixel samples are integral. + + // Samples with TransferType DataBuffer.TYPE_BYTE, + // DataBuffer.TYPE_USHORT, DataBuffer.Short and + // DataBuffer.TYPE_INT - integral. + + /** + * The scale factors. + */ + private float scaleFactors[]; // Array of factors for reduction components + + // values into the form scaled from 0 to 255 + + /** + * The donot support unnormalized. + */ + private boolean donotSupportUnnormalized; // This Color Model don't support + + // unnormolized form + + /** + * The need alpha divide. + */ + private boolean needAlphaDivide; // hasAlpha && isAlphaPremultiplied + + /** + * The calc value. + */ + private boolean calcValue; // Value was culculated + + /** + * The need scale. + */ + private boolean needScale; // Normalized value need to scale + + /** + * The min vals. + */ + private float minVals[]; // Array of Min normalized values + + /** + * The ranges. + */ + private float ranges[]; // Array of range normalized values + + /** + * The alpha lut. + */ + private byte alphaLUT[]; // Lookup table for scale alpha value + + /** + * The color lu ts. + */ + private byte colorLUTs[][]; // Lookup tables for scale color values + + /** + * The from_ linea r_ rg b_ lut. + */ + private byte from_LINEAR_RGB_LUT[]; // Lookup table for conversion from + + // Linear RGB Color Space into sRGB + + /** + * The to_ linea r_8 rg b_ lut. + */ + private byte to_LINEAR_8RGB_LUT[]; // Lookup table for conversion from + + // sRGB Color Space into Linear RGB + // 8 bit + + /** + * The to_ linea r_16 rg b_ lut. + */ + private short to_LINEAR_16RGB_LUT[]; // Lookup table for conversion from + + // sRGB Color Space into Linear RGB + // 16 bit + + /** + * The LINEA r_ rg b_ length. + */ + private int LINEAR_RGB_Length; // Linear RGB bit length + + /** + * The factor. + */ + private float fFactor; // Scale factor + + /** + * The is_s rgb. + */ + private boolean is_sRGB; // ColorModel has sRGB ColorSpace + + /** + * The is_ linea r_ rgb. + */ + private boolean is_LINEAR_RGB; // Color Model has Linear RGB Color + + // Space + + /** + * Instantiates a new component color model. + * + * @param colorSpace + * the color space. + * @param bits + * the array of component masks. + * @param hasAlpha + * whether the color model has alpha. + * @param isAlphaPremultiplied + * whether the alpha is pre-multiplied. + * @param transparency + * the transparency strategy, @see java.awt.Transparency. + * @param transferType + * the transfer type (primitive java type to use for the + * components). + */ + public ComponentColorModel(ColorSpace colorSpace, int bits[], boolean hasAlpha, + boolean isAlphaPremultiplied, int transparency, int transferType) { + super(createPixelBits(colorSpace, hasAlpha, transferType), validateBits(bits, colorSpace, + hasAlpha, transferType), colorSpace, hasAlpha, isAlphaPremultiplied, transparency, + transferType); + + needScale = false; + switch (transferType) { + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_INT: + signed = false; + integral = true; + donotSupportUnnormalized = false; + scaleFactors = new float[numComponents]; + for (int i = 0; i < numColorComponents; i++) { + scaleFactors[i] = 1.0f / maxValues[i]; + if (cs.getMinValue(i) != 0.0f || cs.getMaxValue(i) != 1.0f) { + donotSupportUnnormalized = true; + } + } + if (hasAlpha) { + maxValues[numColorComponents] = (1 << bits[numColorComponents]) - 1; + scaleFactors[numColorComponents] = 1.0f / maxValues[numColorComponents]; + } + break; + case DataBuffer.TYPE_SHORT: + signed = true; + integral = true; + donotSupportUnnormalized = true; + scaleFactors = new float[numComponents]; + for (int i = 0; i < numComponents; i++) { + maxValues[i] = Short.MAX_VALUE; + scaleFactors[i] = 1.0f / maxValues[i]; + if (cs.getMinValue(i) != 0.0f || cs.getMaxValue(i) != 1.0f) { + needScale = true; + } + } + if (needScale) { + minVals = new float[numColorComponents]; + ranges = new float[numColorComponents]; + for (int i = 0; i < numColorComponents; i++) { + minVals[i] = cs.getMinValue(i); + ranges[i] = cs.getMaxValue(i) - minVals[i]; + } + } + break; + case DataBuffer.TYPE_FLOAT: + case DataBuffer.TYPE_DOUBLE: + signed = true; + integral = false; + donotSupportUnnormalized = true; + break; + default: + // awt.215=transferType is not one of DataBuffer.TYPE_BYTE, + // DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, + // DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or + // DataBuffer.TYPE_DOUBLE + throw new IllegalArgumentException(Messages.getString("awt.215")); //$NON-NLS-1$ + } + + needAlphaDivide = hasAlpha && isAlphaPremultiplied; + initLUTs(); + } + + /** + * Instantiates a new component color model. + * + * @param colorSpace + * the color space. + * @param hasAlpha + * whether the color model has alpha. + * @param isAlphaPremultiplied + * whether the alpha is pre-multiplied. + * @param transparency + * the transparency strategy, @see java.awt.Transparency. + * @param transferType + * the transfer type (primitive java type to use for the + * components). + */ + public ComponentColorModel(ColorSpace colorSpace, boolean hasAlpha, + boolean isAlphaPremultiplied, int transparency, int transferType) { + + this(colorSpace, createPixelBitsArray(colorSpace, hasAlpha, transferType), hasAlpha, + isAlphaPremultiplied, transparency, transferType); + } + + /** + * Validate bits. + * + * @param bits + * the bits. + * @param colorSpace + * the color space. + * @param hasAlpha + * the has alpha. + * @param transferType + * the transfer type. + * @return the int[]. + */ + private static int[] validateBits(int bits[], ColorSpace colorSpace, boolean hasAlpha, + int transferType) { + if (bits != null) { + return bits; + } + + int numComponents = colorSpace.getNumComponents(); + if (hasAlpha) { + numComponents++; + } + bits = new int[numComponents]; + + int componentLength = DataBuffer.getDataTypeSize(transferType); + + for (int i = 0; i < numComponents; i++) { + bits[i] = componentLength; + } + + return bits; + } + + /** + * Creates the pixel bits. + * + * @param colorSpace + * the color space. + * @param hasAlpha + * the has alpha. + * @param transferType + * the transfer type. + * @return the int. + */ + private static int createPixelBits(ColorSpace colorSpace, boolean hasAlpha, int transferType) { + int numComponents = colorSpace.getNumComponents(); + if (hasAlpha) { + numComponents++; + } + int componentLength = DataBuffer.getDataTypeSize(transferType); + return numComponents * componentLength; + } + + /** + * Creates the pixel bits array. + * + * @param colorSpace + * the color space. + * @param hasAlpha + * the has alpha. + * @param transferType + * the transfer type. + * @return the int[]. + */ + private static int[] createPixelBitsArray(ColorSpace colorSpace, boolean hasAlpha, + int transferType) { + + int numComponents = colorSpace.getNumComponents(); + if (hasAlpha) { + numComponents++; + } + + int bits[] = new int[numComponents]; + for (int i = 0; i < numComponents; i++) { + bits[i] = DataBuffer.getDataTypeSize(transferType); + } + return bits; + } + + @Override + public Object getDataElements(int components[], int offset, Object obj) { + if (donotSupportUnnormalized) { + // awt.213=This ComponentColorModel does not support the + // unnormalized form + throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$ + } + + if (offset + numComponents > components.length) { + // awt.216=The components array is not large enough to hold all the + // color and alpha components + throw new IllegalArgumentException(Messages.getString("awt.216")); //$NON-NLS-1$ + } + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[]; + if (obj == null) { + ba = new byte[numComponents]; + } else { + ba = (byte[])obj; + } + for (int i = 0, idx = offset; i < numComponents; i++, idx++) { + ba[i] = (byte)components[idx]; + } + return ba; + case DataBuffer.TYPE_USHORT: + short sa[]; + if (obj == null) { + sa = new short[numComponents]; + } else { + sa = (short[])obj; + } + for (int i = 0, idx = offset; i < numComponents; i++, idx++) { + sa[i] = (short)components[idx]; + } + return sa; + case DataBuffer.TYPE_INT: + int ia[]; + if (obj == null) { + ia = new int[numComponents]; + } else { + ia = (int[])obj; + } + for (int i = 0, idx = offset; i < numComponents; i++, idx++) { + ia[i] = components[idx]; + } + return ia; + default: + // awt.217=The transfer type of this ComponentColorModel is not + // one + // of the following transfer types: DataBuffer.TYPE_BYTE, + // DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT + throw new UnsupportedOperationException(Messages.getString("awt.217")); //$NON-NLS-1$ + } + } + + @Override + public Object getDataElements(float normComponents[], int normOffset, Object obj) { + if (needScale) { + for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) { + normComponents[idx] = (normComponents[idx] - minVals[i]) / ranges[i]; + } + } + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[]; + if (obj == null) { + ba = new byte[numComponents]; + } else { + ba = (byte[])obj; + } + + if (needAlphaDivide) { + float alpha = normComponents[normOffset + numColorComponents]; + for (int i = 0, idx = normOffset; i < numColorComponents; i++, idx++) { + ba[i] = (byte)(normComponents[idx] * alpha * maxValues[i] + 0.5f); + } + ba[numColorComponents] = (byte)(normComponents[normOffset + numColorComponents] + * maxValues[numColorComponents] + 0.5f); + } else { + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + ba[idx] = (byte)(normComponents[idx] * maxValues[i] + 0.5f); + } + } + return ba; + + case DataBuffer.TYPE_USHORT: + short usa[]; + if (obj == null) { + usa = new short[numComponents]; + } else { + usa = (short[])obj; + } + + if (needAlphaDivide) { + float alpha = normComponents[normOffset + numColorComponents]; + for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) { + usa[i] = (short)(normComponents[idx] * alpha * maxValues[i] + 0.5f); + } + usa[numColorComponents] = (short)(alpha * maxValues[numColorComponents] + 0.5f); + } else { + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + usa[i] = (short)(normComponents[idx] * maxValues[i] + 0.5f); + } + } + return usa; + + case DataBuffer.TYPE_INT: + int ia[]; + if (obj == null) { + ia = new int[numComponents]; + } else { + ia = (int[])obj; + } + + if (needAlphaDivide) { + float alpha = normComponents[normOffset + numColorComponents]; + for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) { + ia[i] = (int)(normComponents[idx] * alpha * maxValues[i] + 0.5f); + } + ia[numColorComponents] = (int)(alpha * maxValues[numColorComponents] + 0.5f); + } else { + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + ia[i] = (int)(normComponents[idx] * maxValues[i] + 0.5f); + } + } + return ia; + + case DataBuffer.TYPE_SHORT: + short sa[]; + if (obj == null) { + sa = new short[numComponents]; + } else { + sa = (short[])obj; + } + + if (needAlphaDivide) { + float alpha = normComponents[normOffset + numColorComponents]; + for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) { + sa[i] = (short)(normComponents[idx] * alpha * maxValues[i] + 0.5f); + } + sa[numColorComponents] = (short)(alpha * maxValues[numColorComponents] + 0.5f); + } else { + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + sa[i] = (short)(normComponents[idx] * maxValues[i] + 0.5f); + } + } + return sa; + + case DataBuffer.TYPE_FLOAT: + float fa[]; + if (obj == null) { + fa = new float[numComponents]; + } else { + fa = (float[])obj; + } + + if (needAlphaDivide) { + float alpha = normComponents[normOffset + numColorComponents]; + for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) { + fa[i] = normComponents[idx] * alpha; + } + fa[numColorComponents] = alpha; + } else { + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + fa[i] = normComponents[idx]; + } + } + return fa; + + case DataBuffer.TYPE_DOUBLE: + double da[]; + if (obj == null) { + da = new double[numComponents]; + } else { + da = (double[])obj; + } + + if (needAlphaDivide) { + double alpha = normComponents[normOffset + numColorComponents]; + for (int i = 0, idx = 0; i < numColorComponents; i++, idx++) { + da[i] = normComponents[idx] * alpha; + } + da[numColorComponents] = alpha; + } else { + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + da[i] = normComponents[idx]; + } + } + return da; + + default: + // awt.213=This ComponentColorModel does not support the + // unnormalized form + throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$ + } + } + + @Override + public Object getDataElements(int rgb, Object pixel) { + float normComp[]; + float comp[]; + + int red = (rgb >> 16) & 0xff; + int green = (rgb >> 8) & 0xff; + int blue = rgb & 0xff; + int alpha = (rgb >> 24) & 0xff; + + comp = new float[3]; + if (is_sRGB || is_LINEAR_RGB) { + if (is_LINEAR_RGB) { + if (LINEAR_RGB_Length == 8) { + red = to_LINEAR_8RGB_LUT[red] & 0xff; + green = to_LINEAR_8RGB_LUT[green] & 0xff; + blue = to_LINEAR_8RGB_LUT[blue] & 0xff; + } else { + red = to_LINEAR_16RGB_LUT[red] & 0xffff; + green = to_LINEAR_16RGB_LUT[green] & 0xffff; + blue = to_LINEAR_16RGB_LUT[blue] & 0xffff; + } + } + comp[0] = red / fFactor; + comp[1] = green / fFactor; + comp[2] = blue / fFactor; + if (!hasAlpha) { + normComp = comp; + } else { + float normAlpha = alpha / 255.0f; + normComp = new float[numComponents]; + for (int i = 0; i < numColorComponents; i++) { + normComp[i] = comp[i]; + } + normComp[numColorComponents] = normAlpha; + } + } else { + comp[0] = red / fFactor; + comp[1] = green / fFactor; + comp[2] = blue / fFactor; + float[] defComp = cs.fromRGB(comp); + if (!hasAlpha) { + normComp = defComp; + } else { + float normAlpha = alpha / 255.0f; + normComp = new float[numComponents]; + for (int i = 0; i < numColorComponents; i++) { + normComp[i] = defComp[i]; + } + normComp[numColorComponents] = normAlpha; + } + } + if (hasAlpha && isAlphaPremultiplied) { + normComp[0] *= normComp[numColorComponents]; + normComp[1] *= normComp[numColorComponents]; + normComp[2] *= normComp[numColorComponents]; + } + + return getDataElements(normComp, 0, pixel); + } + + @Override + public WritableRaster getAlphaRaster(WritableRaster raster) { + if (!hasAlpha) { + return null; + } + + int x = raster.getMinX(); + int y = raster.getMinY(); + int bandList[] = new int[1]; + bandList[0] = raster.getNumBands() - 1; + + return raster.createWritableChild(x, y, raster.getWidth(), raster.getHeight(), x, y, + bandList); + } + + @Override + public ColorModel coerceData(WritableRaster raster, boolean isAlphaPremultiplied) { + if (!hasAlpha || this.isAlphaPremultiplied == isAlphaPremultiplied) { + return this; + } + + int minX = raster.getMinX(); + int minY = raster.getMinY(); + int w = raster.getWidth(); + int h = raster.getHeight(); + + if (isAlphaPremultiplied) { + switch (transferType) { + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_INT: + float alphaFactor = maxValues[numColorComponents]; + int iComponents[] = null; + int iTransparentComponents[] = new int[numComponents]; + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + iComponents = raster.getPixel(x, minY, iComponents); + if (iComponents[numColorComponents] == 0) { + raster.setPixel(x, minY, iTransparentComponents); + } else { + float alpha = iComponents[numColorComponents] / alphaFactor; + for (int n = 0; n < numColorComponents; n++) { + iComponents[n] = (int)(alpha * iComponents[n] + 0.5f); + } + raster.setPixel(x, minY, iComponents); + } + } + + } + break; + + case DataBuffer.TYPE_SHORT: + float sAlphaFactor = maxValues[numColorComponents]; + short sComponents[] = null; + short sTransparentComponents[] = new short[numComponents]; + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + sComponents = (short[])raster.getDataElements(x, minY, sComponents); + if (sComponents[numColorComponents] == 0) { + raster.setDataElements(x, minY, sTransparentComponents); + } else { + float alpha = sComponents[numColorComponents] / sAlphaFactor; + for (int n = 0; n < numColorComponents; n++) { + sComponents[n] = (byte)(alpha * sComponents[n] + 0.5f); + } + raster.setDataElements(x, minY, sComponents); + } + } + + } + break; + + case DataBuffer.TYPE_FLOAT: + float fComponents[] = null; + float fTransparentComponents[] = new float[numComponents]; + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + fComponents = raster.getPixel(x, minY, fComponents); + if (fComponents[numColorComponents] == 0.0f) { + raster.setDataElements(x, minY, fTransparentComponents); + } else { + float alpha = fComponents[numColorComponents]; + for (int n = 0; n < numColorComponents; n++) { + fComponents[n] = fComponents[n] * alpha; + } + raster.setPixel(x, minY, fComponents); + } + } + + } + break; + + case DataBuffer.TYPE_DOUBLE: + double dComponents[] = null; + double dTransparentComponents[] = new double[numComponents]; + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + dComponents = raster.getPixel(x, minY, dComponents); + if (dComponents[numColorComponents] == 0.0) { + raster.setPixel(x, minY, dTransparentComponents); + } else { + double alpha = dComponents[numColorComponents]; + for (int n = 0; n < numColorComponents; n++) { + dComponents[n] = dComponents[n] * alpha; + } + raster.setPixel(x, minY, dComponents); + } + } + + } + break; + + default: + // awt.219=This transferType is not supported by this color + // model + throw new UnsupportedOperationException(Messages.getString("awt.219")); //$NON-NLS-1$ + } + } else { + switch (transferType) { + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_INT: + float alphaFactor = maxValues[numColorComponents]; + int iComponents[] = null; + int iTransparentComponents[] = new int[numComponents]; + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + iComponents = raster.getPixel(x, minY, iComponents); + if (iComponents[numColorComponents] == 0) { + raster.setPixel(x, minY, iTransparentComponents); + } else { + float alpha = iComponents[numColorComponents] / alphaFactor; + for (int n = 0; n < numColorComponents; n++) { + iComponents[n] = (int)(iComponents[n] / alpha + 0.5f); + } + raster.setPixel(x, minY, iComponents); + } + } + + } + break; + + case DataBuffer.TYPE_SHORT: + float sAlphaFactor = maxValues[numColorComponents]; + short sComponents[] = null; + short sTransparentComponents[] = new short[numComponents]; + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + sComponents = (short[])raster.getDataElements(x, minY, sComponents); + if (sComponents[numColorComponents] == 0) { + raster.setDataElements(x, minY, sTransparentComponents); + } else { + float alpha = sComponents[numColorComponents] / sAlphaFactor; + for (int n = 0; n < numColorComponents; n++) { + sComponents[n] = (byte)(sComponents[n] / alpha + 0.5f); + } + raster.setDataElements(x, minY, sComponents); + } + } + + } + break; + + case DataBuffer.TYPE_FLOAT: + float fComponents[] = null; + float fTransparentComponents[] = new float[numComponents]; + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + fComponents = raster.getPixel(x, minY, fComponents); + if (fComponents[numColorComponents] == 0.0f) { + raster.setDataElements(x, minY, fTransparentComponents); + } else { + float alpha = fComponents[numColorComponents]; + for (int n = 0; n < numColorComponents; n++) { + fComponents[n] = fComponents[n] / alpha; + } + raster.setPixel(x, minY, fComponents); + } + } + + } + break; + + case DataBuffer.TYPE_DOUBLE: + double dComponents[] = null; + double dTransparentComponents[] = new double[numComponents]; + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + dComponents = raster.getPixel(x, minY, dComponents); + if (dComponents[numColorComponents] == 0.0) { + raster.setPixel(x, minY, dTransparentComponents); + } else { + double alpha = dComponents[numColorComponents]; + for (int n = 0; n < numColorComponents; n++) { + dComponents[n] = dComponents[n] / alpha; + } + raster.setPixel(x, minY, dComponents); + } + } + + } + break; + default: + // awt.219=This transferType is not supported by this color + // model + throw new UnsupportedOperationException(Messages.getString("awt.219")); //$NON-NLS-1$ + } + } + + if (!signed) { + return new ComponentColorModel(cs, bits, hasAlpha, isAlphaPremultiplied, transparency, + transferType); + } + + return new ComponentColorModel(cs, null, hasAlpha, isAlphaPremultiplied, transparency, + transferType); + } + + @Override + public int[] getComponents(Object pixel, int[] components, int offset) { + if (donotSupportUnnormalized) { + // awt.213=This ComponentColorModel does not support the + // unnormalized form + throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$ + } + + if (components == null) { + components = new int[offset + numComponents]; + } else if (offset + numComponents > components.length) { + // awt.218=The components array is not large enough to hold all the + // color and alpha components + throw new IllegalArgumentException(Messages.getString("awt.218")); //$NON-NLS-1$ + } + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[])pixel; + + for (int i = 0, idx = offset; i < numComponents; i++, idx++) { + components[idx] = ba[i] & 0xff; + } + return components; + + case DataBuffer.TYPE_USHORT: + short sa[] = (short[])pixel; + for (int i = 0, idx = offset; i < numComponents; i++, idx++) { + components[idx] = sa[i] & 0xffff; + } + return components; + + case DataBuffer.TYPE_INT: + int ia[] = (int[])pixel; + for (int i = 0, idx = offset; i < numComponents; i++, idx++) { + components[idx] = ia[i]; + } + return components; + + default: + // awt.217=The transfer type of this ComponentColorModel is not + // one + // of the following transfer types: DataBuffer.TYPE_BYTE, + // DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT + throw new UnsupportedOperationException(Messages.getString("awt.217")); //$NON-NLS-1$ + } + + } + + @Override + public float[] getNormalizedComponents(Object pixel, float normComponents[], int normOffset) { + + if (normComponents == null) { + normComponents = new float[numComponents + normOffset]; + } + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[])pixel; + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + normComponents[idx] = (ba[i] & 0xff) * scaleFactors[i]; + } + break; + + case DataBuffer.TYPE_USHORT: + short usa[] = (short[])pixel; + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + normComponents[idx] = (usa[i] & 0xffff) * scaleFactors[i]; + } + break; + + case DataBuffer.TYPE_INT: + int ia[] = (int[])pixel; + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + normComponents[idx] = ia[i] * scaleFactors[i]; + } + break; + + case DataBuffer.TYPE_SHORT: + short sa[] = (short[])pixel; + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + normComponents[idx] = sa[i] * scaleFactors[i]; + } + break; + + case DataBuffer.TYPE_FLOAT: + float fa[] = (float[])pixel; + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + normComponents[idx] = fa[i]; + } + break; + + case DataBuffer.TYPE_DOUBLE: + double da[] = (double[])pixel; + for (int i = 0, idx = normOffset; i < numComponents; i++, idx++) { + normComponents[idx] = (float)da[i]; + } + break; + + default: + // awt.21A=This ComponentColorModel does not support this + // transferType + throw new IllegalArgumentException(Messages.getString("awt.21A")); //$NON-NLS-1$ + } + + if (needAlphaDivide) { + float alpha = normComponents[normOffset + numColorComponents]; + for (int i = 0, idx = normOffset; i < numColorComponents; i++, idx++) { + normComponents[idx] /= alpha; + } + } + + if (needScale) { + for (int i = 0, idx = normOffset; i < numColorComponents; i++, idx++) { + normComponents[idx] = minVals[i] + ranges[i] * normComponents[idx]; + } + } + return normComponents; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ComponentColorModel)) { + return false; + } + return super.equals(obj); + } + + @Override + public int getRed(Object inData) { + return getRGBComponent(inData, 0); + } + + @Override + public int getRGB(Object inData) { + int alpha = getAlpha(inData); + if (cs.getType() == ColorSpace.TYPE_GRAY) { + int gray = getRed(inData); + return (alpha << 24 | gray << 16 | gray << 8 | gray); + } + return (alpha << 24 | getRed(inData) << 16 | getGreen(inData) << 8 | getBlue(inData)); + } + + @Override + public int getGreen(Object inData) { + return getRGBComponent(inData, 1); + } + + @Override + public int getBlue(Object inData) { + return getRGBComponent(inData, 2); + } + + @Override + public int getAlpha(Object inData) { + if (!hasAlpha) { + return 255; + } + int alpha = 0; + + switch (transferType) { + case DataBuffer.TYPE_BYTE: { + byte ba[] = (byte[])inData; + alpha = ba[numColorComponents] & 0xff; + if (bits[numColorComponents] != 8) { + return alphaLUT[alpha] & 0xff; + } + return alpha; + } + case DataBuffer.TYPE_USHORT: { + short usa[] = (short[])inData; + alpha = usa[numColorComponents] & 0xffff; + if (bits[numColorComponents] != 8) { + return alphaLUT[alpha] & 0xff; + } + return alpha; + } + case DataBuffer.TYPE_INT: { + int ia[] = (int[])inData; + alpha = ia[numColorComponents]; + if (bits[numColorComponents] != 8) { + return alphaLUT[alpha] & 0xff; + } + return alpha; + } + case DataBuffer.TYPE_SHORT: { + short sa[] = (short[])inData; + alpha = sa[numColorComponents]; + if (bits[numColorComponents] != 8) { + return alphaLUT[alpha] & 0xff; + } + return alpha; + } + case DataBuffer.TYPE_FLOAT: { + float fa[] = (float[])inData; + return (int)(fa[numColorComponents] * 255.0f + 0.5f); + } + case DataBuffer.TYPE_DOUBLE: { + double da[] = (double[])inData; + return (int)(da[numColorComponents] * 255.0 + 0.5); + } + default: { + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + } + } + } + + @Override + public WritableRaster createCompatibleWritableRaster(int w, int h) { + SampleModel sm = createCompatibleSampleModel(w, h); + DataBuffer db = sm.createDataBuffer(); + return Raster.createWritableRaster(sm, db, null); + } + + @Override + public boolean isCompatibleSampleModel(SampleModel sm) { + if (!(sm instanceof ComponentSampleModel)) { + return false; + } + if (numComponents != sm.getNumBands()) { + return false; + } + if (transferType != sm.getTransferType()) { + return false; + } + return true; + } + + @Override + public SampleModel createCompatibleSampleModel(int w, int h) { + int bandOffsets[] = new int[numComponents]; + for (int i = 0; i < numComponents; i++) { + bandOffsets[i] = i; + } + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_USHORT: + return new PixelInterleavedSampleModel(transferType, w, h, numComponents, w + * numComponents, bandOffsets); + + default: + return new ComponentSampleModel(transferType, w, h, numComponents, w + * numComponents, bandOffsets); + } + } + + @Override + public boolean isCompatibleRaster(Raster raster) { + SampleModel sm = raster.getSampleModel(); + if (!(sm instanceof ComponentSampleModel)) { + return false; + } + + if (sm.getNumBands() != numComponents) { + return false; + } + if (raster.getTransferType() != transferType) { + return false; + } + + int sampleSizes[] = sm.getSampleSize(); + for (int i = 0; i < numComponents; i++) { + if (bits[i] != sampleSizes[i]) { + return false; + } + } + return true; + } + + @Override + public float[] getNormalizedComponents(int components[], int offset, float normComponents[], + int normOffset) { + if (donotSupportUnnormalized) { + // awt.213=This ComponentColorModel does not support the + // unnormalized form + throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$ + } + + return super.getNormalizedComponents(components, offset, normComponents, normOffset); + } + + @Override + public int getDataElement(int[] components, int offset) { + if (numComponents > 1) { + // awt.212=There is more than one component in this ColorModel + throw new IllegalArgumentException(Messages.getString("awt.212")); //$NON-NLS-1$ + } + if (donotSupportUnnormalized) { + // awt.213=This ComponentColorModel does not support the + // unnormalized form + throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$ + } + return components[offset]; + } + + @Override + public int[] getUnnormalizedComponents(float[] normComponents, int normOffset, + int[] components, int offset) { + + if (donotSupportUnnormalized) { + // awt.213=This ComponentColorModel does not support the + // unnormalized form + throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$ + } + + if (normComponents.length - normOffset < numComponents) { + // awt.21B=The length of normComponents minus normOffset is less + // than numComponents + throw new IllegalArgumentException(Messages.getString("awt.21B")); //$NON-NLS-1$ + } + + return super.getUnnormalizedComponents(normComponents, normOffset, components, offset); + } + + @Override + public int getDataElement(float normComponents[], int normOffset) { + if (numComponents > 1) { + // awt.212=There is more than one component in this ColorModel + throw new IllegalArgumentException(Messages.getString("awt.212")); //$NON-NLS-1$ + } + if (signed) { + // awt.210=The component value for this ColorModel is signed + throw new IllegalArgumentException(Messages.getString("awt.210")); //$NON-NLS-1$ + } + + Object pixel = getDataElements(normComponents, normOffset, null); + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[])pixel; + return ba[0] & 0xff; + case DataBuffer.TYPE_USHORT: + short sa[] = (short[])pixel; + return sa[0] & 0xffff; + case DataBuffer.TYPE_INT: + int ia[] = (int[])pixel; + return ia[0]; + default: + // awt.211=Pixel values for this ColorModel are not conveniently + // representable as a single int + throw new IllegalArgumentException(Messages.getString("awt.211")); //$NON-NLS-1$ + } + } + + @Override + public int[] getComponents(int pixel, int components[], int offset) { + if (numComponents > 1) { + // awt.212=There is more than one component in this ColorModel + throw new IllegalArgumentException(Messages.getString("awt.212")); //$NON-NLS-1$ + } + if (donotSupportUnnormalized) { + // awt.213=This ComponentColorModel does not support the + // unnormalized form + throw new IllegalArgumentException(Messages.getString("awt.213")); //$NON-NLS-1$ + } + + if (components == null) { + components = new int[offset + 1]; + } + + components[offset] = pixel & maxValues[0]; + return components; + } + + @Override + public int getRed(int pixel) { + float rgb[] = toRGB(pixel); + return (int)(rgb[0] * 255.0f + 0.5f); + } + + @Override + public int getRGB(int pixel) { + return (getAlpha(pixel) << 24) | (getRed(pixel) << 16) | (getGreen(pixel) << 8) + | getBlue(pixel); + } + + @Override + public int getGreen(int pixel) { + float rgb[] = toRGB(pixel); + return (int)(rgb[1] * 255.0f + 0.5f); + } + + @Override + public int getBlue(int pixel) { + float rgb[] = toRGB(pixel); + return (int)(rgb[2] * 255.0f + 0.5f); + } + + @Override + public int getAlpha(int pixel) { + + // This method throw IllegalArgumentException according to + // Java API Spacification + if (signed) { + // awt.210=The component value for this ColorModel is signed + throw new IllegalArgumentException(Messages.getString("awt.210")); //$NON-NLS-1$ + } + + if (numComponents > 1) { + // awt.212=There is more than one component in this ColorModel + throw new IllegalArgumentException(Messages.getString("awt.212")); //$NON-NLS-1$ + } + + return 255; + } + + /** + * Initialization of Lookup tables. + */ + private void initLUTs() { + is_sRGB = cs.isCS_sRGB(); + is_LINEAR_RGB = (cs == LUTColorConverter.LINEAR_RGB_CS); + + if (hasAlpha && bits[numColorComponents] != 8 && integral) { + alphaLUT = new byte[maxValues[numColorComponents] + 1]; + for (int i = 0; i <= maxValues[numColorComponents]; i++) { + alphaLUT[i] = (byte)(scaleFactors[numColorComponents] * i + 0.5f); + } + } + + if (is_LINEAR_RGB) { + if (maxBitLength > 8) { + LINEAR_RGB_Length = 16; + from_LINEAR_RGB_LUT = LUTColorConverter.getFrom16lRGBtosRGB_LUT(); + to_LINEAR_16RGB_LUT = LUTColorConverter.getFromsRGBto16lRGB_LUT(); + } else { + LINEAR_RGB_Length = 8; + from_LINEAR_RGB_LUT = LUTColorConverter.getFrom8lRGBtosRGB_LUT(); + to_LINEAR_8RGB_LUT = LUTColorConverter.getFromsRGBto8lRGB_LUT(); + } + fFactor = ((1 << LINEAR_RGB_Length) - 1); + } else { + fFactor = 255.0f; + } + + if (!isAlphaPremultiplied && integral) { + colorLUTs = new byte[3][]; + + if (is_sRGB) { + for (int i = 0; i < numColorComponents; i++) { + if (bits[i] != 8) { + for (int j = 0; j < i; j++) { + if (bits[i] == bits[j]) { + colorLUTs[i] = colorLUTs[j]; + break; + } + } + colorLUTs[i] = new byte[maxValues[i] + 1]; + for (int j = 0; j <= maxValues[0]; j++) { + colorLUTs[i][j] = (byte)(scaleFactors[i] * j + 0.5f); + } + } + } + } + + if (is_LINEAR_RGB) { + + for (int i = 0; i < numColorComponents; i++) { + if (bits[i] != LINEAR_RGB_Length) { + for (int j = 0; j < i; j++) { + if (bits[i] == bits[j]) { + colorLUTs[i] = colorLUTs[j]; + break; + } + } + colorLUTs[i] = new byte[maxValues[i] + 1]; + for (int j = 0; j <= maxValues[0]; j++) { + int idx; + if (LINEAR_RGB_Length == 8) { + idx = (int)(scaleFactors[i] * j + 0.5f); + } else { + idx = (int)(scaleFactors[i] * j * 257.0f + 0.5f); + } + colorLUTs[i][j] = from_LINEAR_RGB_LUT[idx]; + } + } + } + } + + } + } + + /** + * To rgb. + * + * @param pixel + * the integer representation of the pixel. + * @return the array of normalized sRGB components. + */ + private float[] toRGB(int pixel) { + + // This method throw IllegalArgumentException according to + // Java API Spacification + if (signed) { + // awt.210=The component value for this ColorModel is signed + throw new IllegalArgumentException(Messages.getString("awt.210")); //$NON-NLS-1$ + } + + if (numComponents > 1) { + // awt.212=There is more than one component in this ColorModel + throw new IllegalArgumentException(Messages.getString("awt.212")); //$NON-NLS-1$ + } + + Object obj = null; + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = new byte[1]; + ba[0] = (byte)pixel; + obj = ba; + break; + + case DataBuffer.TYPE_USHORT: + short sa[] = new short[1]; + sa[0] = (short)pixel; + obj = sa; + break; + + case DataBuffer.TYPE_INT: + int ia[] = new int[1]; + ia[0] = pixel; + obj = ia; + break; + + } + + return cs.toRGB(getNormalizedComponents(obj, null, 0)); + } + + /** + * Gets the RGB component. + * + * @param pixel + * the pixel. + * @param idx + * the index of component. + * @return the RGB value from 0 to 255 pixel's component. + */ + private int getRGBComponent(Object pixel, int idx) { + if (is_sRGB) { + int comp = getDefComponent(pixel, idx); + if (calcValue || bits[idx] == 8) { + return comp; + } + return colorLUTs[idx][comp] & 0xff; + } else if (is_LINEAR_RGB) { + int comp = getDefComponent(pixel, idx); + if (calcValue || bits[idx] == LINEAR_RGB_Length) { + return from_LINEAR_RGB_LUT[comp] & 0xff; + } + return colorLUTs[idx][comp] & 0xff; + } + + float normComp[] = getNormalizedComponents(pixel, null, 0); + float rgbComp[] = cs.toRGB(normComp); + return (int)(rgbComp[idx] * 255.0f + 0.5f); + } + + /** + * Gets the def component. + * + * @param pixel + * the pixel. + * @param idx + * the index of component. + * @return the tentative value of the pixel component. + */ + private int getDefComponent(Object pixel, int idx) { + int comp = 0; + calcValue = false; + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[])pixel; + comp = ba[idx] & 0xff; + if (needAlphaDivide) { + int alpha = ba[numColorComponents] & 0xff; + if (alpha == 0) { + comp = 0; + } else { + float normAlpha = scaleFactors[numColorComponents] * alpha; + comp = (int)(comp * fFactor / normAlpha + 0.5f); + } + calcValue = true; + } + return comp; + + case DataBuffer.TYPE_USHORT: + short usa[] = (short[])pixel; + comp = usa[idx] & 0xffff; + if (needAlphaDivide) { + int alpha = usa[numColorComponents] & 0xffff; + if (alpha == 0) { + comp = 0; + } else { + float normAlpha = scaleFactors[numColorComponents] * alpha; + comp = (int)(comp * fFactor / normAlpha + 0.5f); + } + calcValue = true; + } + return comp; + + case DataBuffer.TYPE_INT: + int ia[] = (int[])pixel; + comp = ia[idx]; + if (needAlphaDivide) { + int alpha = ia[numColorComponents]; + if (alpha == 0) { + comp = 0; + } else { + float normAlpha = scaleFactors[numColorComponents] * alpha; + comp = (int)(comp * fFactor / normAlpha + 0.5f); + } + calcValue = true; + } + return comp; + + case DataBuffer.TYPE_SHORT: + short sa[] = (short[])pixel; + comp = sa[idx]; + if (needAlphaDivide) { + int alpha = sa[numColorComponents]; + if (alpha == 0) { + comp = 0; + } else { + float normAlpha = scaleFactors[numColorComponents] * alpha; + comp = (int)(comp * fFactor / normAlpha + 0.5f); + } + calcValue = true; + } + return comp; + + case DataBuffer.TYPE_FLOAT: + float fa[] = (float[])pixel; + if (needAlphaDivide) { + float alpha = fa[numColorComponents]; + if (fa[numColorComponents] == 0.0f) { + comp = 0; + } else { + comp = (int)(fa[idx] * fFactor / alpha + 0.5f); + } + } else { + comp = (int)(fa[idx] * fFactor + 0.5f); + } + calcValue = true; + return comp; + + case DataBuffer.TYPE_DOUBLE: + double da[] = (double[])pixel; + if (needAlphaDivide) { + if (da[numColorComponents] == 0.0) { + comp = 0; + } else { + comp = (int)(da[idx] * fFactor / da[numColorComponents] + 0.5); + } + } else { + comp = (int)(da[idx] * fFactor + 0.5); + } + calcValue = true; + return comp; + + default: + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + } + } + +} diff --git a/app/src/main/java/java/awt/image/ComponentSampleModel.java b/app/src/main/java/java/awt/image/ComponentSampleModel.java new file mode 100644 index 000000000..7f8140918 --- /dev/null +++ b/app/src/main/java/java/awt/image/ComponentSampleModel.java @@ -0,0 +1,705 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.util.Arrays; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The ComponentSampleModel class represents a set of image data whose each + * element - the sample of a pixel - takes one data element of the DataBuffer. + *

+ * The Bank indices denote the correspondence between the bank of data buffers + * and a band of image data. The Pixel stride is the number of data array + * elements between two samples for the same band on the same scanline. The + * pixel stride for a BandedSampleModel is one. The scanline stride represents + * the number of data array elements between a specified sample and the + * corresponding sample in the same column in the next scanline. The array of + * band offsets gives the starting offsets within each data banks of the in the + * DataBuffer. The bank indices represents the indices within each bank of the + * DataBuffer corresponding to a band of image data. + * + * @since Android 1.0 + */ +public class ComponentSampleModel extends SampleModel { + + /** + * The band offsets array of this ComponentSampleModel. + */ + protected int bandOffsets[]; + + /** + * The bank indices array of this ComponentSampleModel. + */ + protected int bankIndices[]; + + /** + * The number of bands in this ComponentSampleModel. + */ + protected int numBands; + + /** + * The number banks of this ComponentSampleModel. + */ + protected int numBanks; + + /** + * The scanline stride of this ComponentSampleModel. + */ + protected int scanlineStride; + + /** + * The pixel stride of this ComponentSampleModel. + */ + protected int pixelStride; + + /** + * Instantiates a new ComponentSampleModel with the specified properties. + * + * @param dataType + * the data type of samples. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param pixelStride + * the pixel stride of the image data. + * @param scanlineStride + * the scanline stride of the image data. + * @param bankIndices + * the array of the bank indices. + * @param bandOffsets + * the array of the band offsets. + */ + public ComponentSampleModel(int dataType, int w, int h, int pixelStride, int scanlineStride, + int bankIndices[], int bandOffsets[]) { + + super(dataType, w, h, bandOffsets.length); + + if (pixelStride < 0) { + // awt.24B=Pixel stride must be >= 0 + throw new IllegalArgumentException(Messages.getString("awt.24B")); //$NON-NLS-1$ + } + + if (scanlineStride < 0) { + // awt.24C=Scanline stride must be >= 0 + throw new IllegalArgumentException(Messages.getString("awt.24C")); //$NON-NLS-1$ + } + + if (bankIndices.length != bandOffsets.length) { + // awt.24D=Bank Indices length must be equal Bank Offsets length + throw new IllegalArgumentException(Messages.getString("awt.24D")); //$NON-NLS-1$ + } + + this.pixelStride = pixelStride; + this.scanlineStride = scanlineStride; + this.bandOffsets = bandOffsets.clone(); + this.bankIndices = bankIndices.clone(); + this.numBands = bandOffsets.length; + + int maxBank = 0; + for (int i = 0; i < bankIndices.length; i++) { + if (bankIndices[i] < 0) { + // awt.24E=Index of {0} bank must be >= 0 + throw new IllegalArgumentException(Messages.getString("awt.24E", i)); //$NON-NLS-1$ + } + if (bankIndices[i] > maxBank) { + maxBank = bankIndices[i]; + } + } + this.numBanks = maxBank + 1; + + } + + /** + * Instantiates a new ComponentSampleModel with the specified properties. + * + * @param dataType + * the data type of the samples. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param pixelStride + * the pixel stride of the image data. + * @param scanlineStride + * the scanline stride of the image data. + * @param bandOffsets + * the band offsets. + */ + public ComponentSampleModel(int dataType, int w, int h, int pixelStride, int scanlineStride, + int bandOffsets[]) { + + super(dataType, w, h, bandOffsets.length); + if (pixelStride < 0) { + // awt.24B=Pixel stride must be >= 0 + throw new IllegalArgumentException(Messages.getString("awt.24B")); //$NON-NLS-1$ + } + + if (scanlineStride < 0) { + // awt.24C=Scanline stride must be >= 0 + throw new IllegalArgumentException(Messages.getString("awt.24C")); //$NON-NLS-1$ + } + + this.pixelStride = pixelStride; + this.scanlineStride = scanlineStride; + this.bandOffsets = bandOffsets.clone(); + this.numBands = bandOffsets.length; + this.numBanks = 1; + + this.bankIndices = new int[numBands]; + for (int i = 0; i < numBands; i++) { + bankIndices[i] = 0; + } + } + + @Override + public Object getDataElements(int x, int y, Object obj, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + switch (dataType) { + case DataBuffer.TYPE_BYTE: + byte bdata[]; + if (obj == null) { + bdata = new byte[numBands]; + } else { + bdata = (byte[])obj; + } + + for (int i = 0; i < numBands; i++) { + bdata[i] = (byte)getSample(x, y, i, data); + } + + obj = bdata; + break; + + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: + short sdata[]; + if (obj == null) { + sdata = new short[numBands]; + } else { + sdata = (short[])obj; + } + + for (int i = 0; i < numBands; i++) { + sdata[i] = (short)getSample(x, y, i, data); + } + + obj = sdata; + break; + + case DataBuffer.TYPE_INT: + int idata[]; + if (obj == null) { + idata = new int[numBands]; + } else { + idata = (int[])obj; + } + + for (int i = 0; i < numBands; i++) { + idata[i] = getSample(x, y, i, data); + } + + obj = idata; + break; + + case DataBuffer.TYPE_FLOAT: + float fdata[]; + if (obj == null) { + fdata = new float[numBands]; + } else { + fdata = (float[])obj; + } + + for (int i = 0; i < numBands; i++) { + fdata[i] = getSampleFloat(x, y, i, data); + } + + obj = fdata; + break; + + case DataBuffer.TYPE_DOUBLE: + double ddata[]; + if (obj == null) { + ddata = new double[numBands]; + } else { + ddata = (double[])obj; + } + + for (int i = 0; i < numBands; i++) { + ddata[i] = getSampleDouble(x, y, i, data); + } + + obj = ddata; + break; + } + + return obj; + } + + @Override + public void setDataElements(int x, int y, Object obj, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + switch (dataType) { + case DataBuffer.TYPE_BYTE: + byte barr[] = (byte[])obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, barr[i] & 0xff, data); + } + break; + + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: + short sarr[] = (short[])obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, sarr[i] & 0xffff, data); + } + break; + + case DataBuffer.TYPE_INT: + int iarr[] = (int[])obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, iarr[i], data); + } + break; + + case DataBuffer.TYPE_FLOAT: + float farr[] = (float[])obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, farr[i], data); + } + break; + + case DataBuffer.TYPE_DOUBLE: + double darr[] = (double[])obj; + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, darr[i], data); + } + break; + } + } + + /** + * Compares this ComponentSampleModel with the specified Object. + * + * @param o + * the Object. + * @return true, if the object is a ComponentSampleModel with identical data + * values to this ComponentSampleModel, false otherwise. + */ + @Override + public boolean equals(Object o) { + if ((o == null) || !(o instanceof ComponentSampleModel)) { + return false; + } + ComponentSampleModel model = (ComponentSampleModel)o; + return this.width == model.width && this.height == model.height + && this.numBands == model.numBands && this.dataType == model.dataType + && Arrays.equals(this.bandOffsets, model.bandOffsets) + && Arrays.equals(this.bankIndices, model.bankIndices) + && this.numBands == model.numBands && this.numBanks == model.numBanks + && this.scanlineStride == model.scanlineStride + && this.pixelStride == model.pixelStride; + } + + /** + * @see java.awt.image.SampleModel#createSubsetSampleModel(int[]) + */ + @Override + public SampleModel createSubsetSampleModel(int bands[]) { + if (bands.length > this.numBands) { + // awt.64=The number of the bands in the subset is greater than the + // number of bands in the sample model + throw new RasterFormatException(Messages.getString("awt.64")); //$NON-NLS-1$ + } + + int indices[] = new int[bands.length]; + int offsets[] = new int[bands.length]; + + for (int i = 0; i < bands.length; i++) { + indices[i] = bankIndices[bands[i]]; + offsets[i] = bandOffsets[bands[i]]; + } + + return new ComponentSampleModel(dataType, width, height, pixelStride, scanlineStride, + indices, offsets); + + } + + @Override + public SampleModel createCompatibleSampleModel(int w, int h) { + return new ComponentSampleModel(dataType, w, h, pixelStride, pixelStride * w, bankIndices, + bandOffsets); + } + + @Override + public int[] getPixel(int x, int y, int iArray[], DataBuffer data) { + int pixel[]; + + if (iArray == null) { + pixel = new int[numBands]; + } else { + pixel = iArray; + } + + for (int i = 0; i < numBands; i++) { + pixel[i] = getSample(x, y, i, data); + } + + return pixel; + } + + @Override + public void setPixel(int x, int y, int iArray[], DataBuffer data) { + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, iArray[i], data); + } + } + + @Override + public int getSample(int x, int y, int b, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + return data.getElem(bankIndices[b], y * scanlineStride + x * pixelStride + bandOffsets[b]); + } + + @Override + public float getSampleFloat(int x, int y, int b, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + return data.getElemFloat(bankIndices[b], y * scanlineStride + x * pixelStride + + bandOffsets[b]); + } + + @Override + public double getSampleDouble(int x, int y, int b, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + return data.getElemDouble(bankIndices[b], y * scanlineStride + x * pixelStride + + bandOffsets[b]); + } + + @Override + public int[] getPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) { + if (x < 0 || y < 0 || x > this.width || x + w > this.width || y > this.height + || y + h > this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int pixels[] = null; + int idx = 0; + + if (iArray == null) { + pixels = new int[w * h * numBands]; + } else { + pixels = iArray; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numBands; n++) { + pixels[idx++] = getSample(j, i, n, data); + } + } + } + + return pixels; + } + + @Override + public void setPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) { + if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int idx = 0; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numBands; n++) { + setSample(j, i, n, iArray[idx++], data); + } + } + } + } + + @Override + public void setSample(int x, int y, int b, int s, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + data.setElem(bankIndices[b], y * scanlineStride + x * pixelStride + bandOffsets[b], s); + } + + @Override + public int[] getSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) { + if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int samples[]; + int idx = 0; + + if (iArray == null) { + samples = new int[w * h]; + } else { + samples = iArray; + } + + if (data == null) { + // awt.295=data is null + throw new NullPointerException(Messages.getString("awt.295")); //$NON-NLS-1$ + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + samples[idx++] = getSample(j, i, b, data); + } + } + + return samples; + } + + @Override + public void setSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) { + if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int idx = 0; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + setSample(j, i, b, iArray[idx++], data); + } + } + } + + @Override + public void setSample(int x, int y, int b, float s, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + data.setElemFloat(bankIndices[b], y * scanlineStride + x * pixelStride + bandOffsets[b], s); + } + + @Override + public void setSample(int x, int y, int b, double s, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + data + .setElemDouble(bankIndices[b], y * scanlineStride + x * pixelStride + + bandOffsets[b], s); + } + + @Override + public DataBuffer createDataBuffer() { + DataBuffer data = null; + + int maxOffset = bandOffsets[0]; + for (int i = 1; i < bandOffsets.length; i++) { + if (bandOffsets[i] > maxOffset) { + maxOffset = bandOffsets[i]; + } + } + int size = (height - 1) * scanlineStride + (width - 1) * pixelStride + maxOffset + 1; + + switch (dataType) { + case DataBuffer.TYPE_BYTE: + data = new DataBufferByte(size, numBanks); + break; + case DataBuffer.TYPE_SHORT: + data = new DataBufferShort(size, numBanks); + break; + case DataBuffer.TYPE_USHORT: + data = new DataBufferUShort(size, numBanks); + break; + case DataBuffer.TYPE_INT: + data = new DataBufferInt(size, numBanks); + break; + case DataBuffer.TYPE_FLOAT: + data = new DataBufferFloat(size, numBanks); + break; + case DataBuffer.TYPE_DOUBLE: + data = new DataBufferDouble(size, numBanks); + break; + } + + return data; + + } + + /** + * Gets the offset of the specified band of the specified pixel. + * + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param b + * the band. + * @return the offset of the specified band of the specified pixel. + */ + public int getOffset(int x, int y, int b) { + return y * scanlineStride + x * pixelStride + bandOffsets[b]; + } + + /** + * Gets the offset of the first band of the specified pixel. + * + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. + * @return the offset of the first band of the specified pixel. + */ + public int getOffset(int x, int y) { + return y * scanlineStride + x * pixelStride + bandOffsets[0]; + } + + @Override + public final int getSampleSize(int band) { + return DataBuffer.getDataTypeSize(dataType); + } + + @Override + public final int[] getSampleSize() { + int sampleSizes[] = new int[numBands]; + int size = DataBuffer.getDataTypeSize(dataType); + + for (int i = 0; i < numBands; i++) { + sampleSizes[i] = size; + } + return sampleSizes; + } + + /** + * Gets an array of bank indices corresponding to this ComponentSampleModel. + * + * @return the array of bank indices. + */ + public final int[] getBankIndices() { + return bankIndices.clone(); + } + + /** + * Gets an array of the band offsets corresponding to this + * ComponentSampleModel. + * + * @return the array of band offsets. + */ + public final int[] getBandOffsets() { + return bandOffsets.clone(); + } + + /** + * Gets a hash code of this ComponentSampleModel object. + * + * @return a hash code of this ComponentSampleModel object. + */ + @Override + public int hashCode() { + int hash = 0; + int tmp = 0; + + hash = width; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= height; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= numBands; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= dataType; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + for (int element : bandOffsets) { + hash ^= element; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + } + for (int element : bankIndices) { + hash ^= element; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + } + hash ^= pixelStride; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + + hash ^= scanlineStride; + return hash; + } + + /** + * Gets the scanline stride of this ComponentSampleModel. + * + * @return the scanline stride of this ComponentSampleModel. + */ + public final int getScanlineStride() { + return scanlineStride; + } + + /** + * Gets the pixel stride. + * + * @return the pixel stride. + */ + public final int getPixelStride() { + return pixelStride; + } + + @Override + public final int getNumDataElements() { + return numBands; + } + +} diff --git a/app/src/main/java/java/awt/image/ConvolveOp.java b/app/src/main/java/java/awt/image/ConvolveOp.java new file mode 100644 index 000000000..4e7b38a4c --- /dev/null +++ b/app/src/main/java/java/awt/image/ConvolveOp.java @@ -0,0 +1,545 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + * + * @date: Sep 29, 2005 + */ + +package java.awt.image; + +import java.awt.*; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.util.Arrays; + +import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The ConvolveOp class convolves from the source data to the destination using + * a convolution kernel. Each output pixel is represented as the result of + * multiplying the kernel and the surround of the input pixel. + * + * @since Android 1.0 + */ +public class ConvolveOp implements BufferedImageOp, RasterOp { + + /** + * The Constant EDGE_ZERO_FILL indicates that pixels at the edge of the + * destination image are set to zero. + */ + public static final int EDGE_ZERO_FILL = 0; + + /** + * The Constant EDGE_NO_OP indicates that pixels at the edge of the source + * image are converted to the edge pixels in the destination without + * modification. + */ + public static final int EDGE_NO_OP = 1; + + /** + * The kernel. + */ + private Kernel kernel; + + /** + * The edge cond. + */ + private int edgeCond; + + /** + * The rhs. + */ + private RenderingHints rhs = null; + + static { + // TODO + // System.loadLibrary("imageops"); + } + + /** + * Instantiates a new ConvolveOp object with the specified Kernel and + * specified edges condition. + * + * @param kernel + * the specified Kernel. + * @param edgeCondition + * the specified edge condition. + * @param hints + * the RenderingHints object, or null. + */ + public ConvolveOp(Kernel kernel, int edgeCondition, RenderingHints hints) { + this.kernel = kernel; + this.edgeCond = edgeCondition; + this.rhs = hints; + } + + /** + * Instantiates a new ConvolveOp object with the specified Kernel and + * EDGE_ZERO_FILL edge condition. + * + * @param kernel + * the specified Kernel. + */ + public ConvolveOp(Kernel kernel) { + this.kernel = kernel; + this.edgeCond = EDGE_ZERO_FILL; + } + + /** + * Gets the Kernel object of this ConvolveOp. + * + * @return the Kernel object of this ConvolveOp. + */ + public final Kernel getKernel() { + return (Kernel)kernel.clone(); + } + + public final RenderingHints getRenderingHints() { + return rhs; + } + + /** + * Gets the edge condition of this ConvolveOp. + * + * @return the edge condition: EDGE_NO_OP or EDGE_ZERO_FILL. + */ + public int getEdgeCondition() { + return edgeCond; + } + + public final Rectangle2D getBounds2D(Raster src) { + return src.getBounds(); + } + + public final Rectangle2D getBounds2D(BufferedImage src) { + return getBounds2D(src.getRaster()); + } + + public final Point2D getPoint2D(Point2D srcPt, Point2D dstPt) { + if (dstPt == null) { + dstPt = new Point2D.Float(); + } + + dstPt.setLocation(srcPt); + return dstPt; + } + + public WritableRaster createCompatibleDestRaster(Raster src) { + return src.createCompatibleWritableRaster(); + } + + public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel dstCM) { + if (dstCM == null) { + dstCM = src.getColorModel(); + } + + if (dstCM instanceof IndexColorModel) { + dstCM = ColorModel.getRGBdefault(); + } + + WritableRaster r = dstCM.isCompatibleSampleModel(src.getSampleModel()) ? src.getRaster() + .createCompatibleWritableRaster(src.getWidth(), src.getHeight()) : dstCM + .createCompatibleWritableRaster(src.getWidth(), src.getHeight()); + + return new BufferedImage(dstCM, r, dstCM.isAlphaPremultiplied(), null); + } + + public final WritableRaster filter(Raster src, WritableRaster dst) { + if (src == null) { // Should throw according to spec + // awt.256=Source raster is null + throw new NullPointerException(Messages.getString("awt.256")); //$NON-NLS-1$ + } + + if (src == dst) { + // awt.257=Source raster is equal to destination + throw new IllegalArgumentException(Messages.getString("awt.257")); //$NON-NLS-1$ + } + + if (dst == null) { + dst = createCompatibleDestRaster(src); + } else if (src.getNumBands() != dst.getNumBands()) { + // awt.258=Number of source bands ({0}) is not equal to number of + // destination bands ({1}) + throw new IllegalArgumentException(Messages.getString( + "awt.258", src.getNumBands(), dst.getNumBands())); //$NON-NLS-1$ + } + + // TODO + // if (ippFilter(src, dst, BufferedImage.TYPE_CUSTOM) != 0) + if (slowFilter(src, dst) != 0) { + // awt.21F=Unable to transform source + throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$ + } + + return dst; + } + + /** + * Slow filter. + * + * @param src + * the src. + * @param dst + * the dst. + * @return the int. + */ + private int slowFilter(Raster src, WritableRaster dst) { + try { + SampleModel sm = src.getSampleModel(); + + int numBands = src.getNumBands(); + int srcHeight = src.getHeight(); + int srcWidth = src.getWidth(); + + int xOrigin = kernel.getXOrigin(); + int yOrigin = kernel.getYOrigin(); + int kWidth = kernel.getWidth(); + int kHeight = kernel.getHeight(); + float[] data = kernel.getKernelData(null); + + int srcMinX = src.getMinX(); + int srcMinY = src.getMinY(); + int dstMinX = dst.getMinX(); + int dstMinY = dst.getMinY(); + + int srcConvMaxX = srcWidth - (kWidth - xOrigin - 1); + int srcConvMaxY = srcHeight - (kHeight - yOrigin - 1); + + int[] maxValues = new int[numBands]; + int[] masks = new int[numBands]; + int[] sampleSizes = sm.getSampleSize(); + + for (int i = 0; i < numBands; i++) { + maxValues[i] = (1 << sampleSizes[i]) - 1; + masks[i] = ~(maxValues[i]); + } + + // Processing bounds + float[] pixels = null; + pixels = src.getPixels(srcMinX, srcMinY, srcWidth, srcHeight, pixels); + float[] newPixels = new float[pixels.length]; + int rowLength = srcWidth * numBands; + if (this.edgeCond == ConvolveOp.EDGE_NO_OP) { + // top + int start = 0; + int length = yOrigin * rowLength; + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(pixels, start, newPixels, start, length); + // bottom + start = (srcHeight - (kHeight - yOrigin - 1)) * rowLength; + length = (kHeight - yOrigin - 1) * rowLength; + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(pixels, start, newPixels, start, length); + // middle + length = xOrigin * numBands; + int length1 = (kWidth - xOrigin - 1) * numBands; + start = yOrigin * rowLength; + int start1 = (yOrigin + 1) * rowLength - length1; + for (int i = yOrigin; i < (srcHeight - (kHeight - yOrigin - 1)); i++) { + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(pixels, start, newPixels, start, length); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(pixels, start1, newPixels, start1, length1); + start += rowLength; + start1 += rowLength; + } + + } + + // Cycle over pixels to be calculated + for (int i = yOrigin; i < srcConvMaxY; i++) { + for (int j = xOrigin; j < srcConvMaxX; j++) { + + // Take kernel data in backward direction, convolution + int kernelIdx = data.length - 1; + + int pixelIndex = i * rowLength + j * numBands; + for (int hIdx = 0, rasterHIdx = i - yOrigin; hIdx < kHeight; hIdx++, rasterHIdx++) { + for (int wIdx = 0, rasterWIdx = j - xOrigin; wIdx < kWidth; wIdx++, rasterWIdx++) { + int curIndex = rasterHIdx * rowLength + rasterWIdx * numBands; + for (int idx = 0; idx < numBands; idx++) { + newPixels[pixelIndex + idx] += data[kernelIdx] + * pixels[curIndex + idx]; + } + kernelIdx--; + } + } + + // Check for overflow now + for (int idx = 0; idx < numBands; idx++) { + if (((int)newPixels[pixelIndex + idx] & masks[idx]) != 0) { + if (newPixels[pixelIndex + idx] < 0) { + newPixels[pixelIndex + idx] = 0; + } else { + newPixels[pixelIndex + idx] = maxValues[idx]; + } + } + } + } + } + + dst.setPixels(dstMinX, dstMinY, srcWidth, srcHeight, newPixels); + } catch (Exception e) { // Something goes wrong, signal error + return 1; + } + return 0; + } + + public final BufferedImage filter(BufferedImage src, BufferedImage dst) { + if (src == null) { + // awt.259=Source image is null + throw new NullPointerException(Messages.getString("awt.259")); //$NON-NLS-1$ + } + + if (src == dst) { + // awt.25A=Source equals to destination + throw new IllegalArgumentException(Messages.getString("awt.25A")); //$NON-NLS-1$ + } + + ColorModel srcCM = src.getColorModel(); + BufferedImage finalDst = null; + + if (srcCM instanceof IndexColorModel) { + src = ((IndexColorModel)srcCM).convertToIntDiscrete(src.getRaster(), true); + srcCM = src.getColorModel(); + } + + if (dst == null) { + dst = createCompatibleDestImage(src, srcCM); + } else { + if (!srcCM.equals(dst.getColorModel())) { + // Treat BufferedImage.TYPE_INT_RGB and + // BufferedImage.TYPE_INT_ARGB as same + if (!((src.getType() == BufferedImage.TYPE_INT_RGB || src.getType() == BufferedImage.TYPE_INT_ARGB) && (dst + .getType() == BufferedImage.TYPE_INT_RGB || dst.getType() == BufferedImage.TYPE_INT_ARGB))) { + finalDst = dst; + dst = createCompatibleDestImage(src, srcCM); + } + } + } + + // Skip alpha channel for TYPE_INT_RGB images + // TODO + // if (ippFilter(src.getRaster(), dst.getRaster(), src.getType()) != 0) + if (slowFilter(src.getRaster(), dst.getRaster()) != 0) { + // awt.21F=Unable to transform source + throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$ + } + + if (finalDst != null) { + Graphics2D g = finalDst.createGraphics(); + g.setComposite(AlphaComposite.Src); + g.drawImage(dst, 0, 0, null); + } else { + finalDst = dst; + } + + return finalDst; + } + + // TODO remove when this method is used + /** + * Ipp filter. + * + * @param src + * the src. + * @param dst + * the dst. + * @param imageType + * the image type. + * @return the int. + */ + @SuppressWarnings("unused") + private int ippFilter(Raster src, WritableRaster dst, int imageType) { + int srcStride, dstStride; + boolean skipChannel = false; + int channels; + int offsets[] = null; + + switch (imageType) { + case BufferedImage.TYPE_INT_RGB: + case BufferedImage.TYPE_INT_BGR: { + channels = 4; + srcStride = src.getWidth() * 4; + dstStride = dst.getWidth() * 4; + skipChannel = true; + break; + } + + case BufferedImage.TYPE_INT_ARGB: + case BufferedImage.TYPE_INT_ARGB_PRE: + case BufferedImage.TYPE_4BYTE_ABGR: + case BufferedImage.TYPE_4BYTE_ABGR_PRE: { + channels = 4; + srcStride = src.getWidth() * 4; + dstStride = dst.getWidth() * 4; + break; + } + + case BufferedImage.TYPE_BYTE_GRAY: { + channels = 1; + srcStride = src.getWidth(); + dstStride = dst.getWidth(); + break; + } + + case BufferedImage.TYPE_3BYTE_BGR: { + channels = 3; + srcStride = src.getWidth() * 3; + dstStride = dst.getWidth() * 3; + break; + } + + case BufferedImage.TYPE_USHORT_GRAY: // TODO - could be done in + // native code? + case BufferedImage.TYPE_USHORT_565_RGB: + case BufferedImage.TYPE_USHORT_555_RGB: + case BufferedImage.TYPE_BYTE_BINARY: { + return slowFilter(src, dst); + } + + default: { + SampleModel srcSM = src.getSampleModel(); + SampleModel dstSM = dst.getSampleModel(); + + if (srcSM instanceof PixelInterleavedSampleModel + && dstSM instanceof PixelInterleavedSampleModel) { + // Check PixelInterleavedSampleModel + if (srcSM.getDataType() != DataBuffer.TYPE_BYTE + || dstSM.getDataType() != DataBuffer.TYPE_BYTE) { + return slowFilter(src, dst); + } + + channels = srcSM.getNumBands(); // Have IPP functions for 1, + // 3 and 4 channels + if (!(channels == 1 || channels == 3 || channels == 4)) { + return slowFilter(src, dst); + } + + srcStride = ((ComponentSampleModel)srcSM).getScanlineStride(); + dstStride = ((ComponentSampleModel)dstSM).getScanlineStride(); + } else if (srcSM instanceof SinglePixelPackedSampleModel + && dstSM instanceof SinglePixelPackedSampleModel) { + // Check SinglePixelPackedSampleModel + SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel)srcSM; + SinglePixelPackedSampleModel sppsm2 = (SinglePixelPackedSampleModel)dstSM; + + channels = sppsm1.getNumBands(); + + // TYPE_INT_RGB, TYPE_INT_ARGB... + if (sppsm1.getDataType() != DataBuffer.TYPE_INT + || sppsm2.getDataType() != DataBuffer.TYPE_INT + || !(channels == 3 || channels == 4)) { + return slowFilter(src, dst); + } + + // Check compatibility of sample models + if (!Arrays.equals(sppsm1.getBitOffsets(), sppsm2.getBitOffsets()) + || !Arrays.equals(sppsm1.getBitMasks(), sppsm2.getBitMasks())) { + return slowFilter(src, dst); + } + + for (int i = 0; i < channels; i++) { + if (sppsm1.getSampleSize(i) != 8) { + return slowFilter(src, dst); + } + } + + if (channels == 3) { // Cannot skip channel, don't know + // which is alpha... + channels = 4; + } + + srcStride = sppsm1.getScanlineStride() * 4; + dstStride = sppsm2.getScanlineStride() * 4; + } else { + return slowFilter(src, dst); + } + + // Fill offsets if there's a child raster + if (src.getParent() != null || dst.getParent() != null) { + if (src.getSampleModelTranslateX() != 0 || src.getSampleModelTranslateY() != 0 + || dst.getSampleModelTranslateX() != 0 + || dst.getSampleModelTranslateY() != 0) { + offsets = new int[4]; + offsets[0] = -src.getSampleModelTranslateX() + src.getMinX(); + offsets[1] = -src.getSampleModelTranslateY() + src.getMinY(); + offsets[2] = -dst.getSampleModelTranslateX() + dst.getMinX(); + offsets[3] = -dst.getSampleModelTranslateY() + dst.getMinY(); + } + } + } + } + + Object srcData, dstData; + AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance(); + try { + srcData = dbAccess.getData(src.getDataBuffer()); + dstData = dbAccess.getData(dst.getDataBuffer()); + } catch (IllegalArgumentException e) { + return -1; // Unknown data buffer type + } + + return ippFilter32f(kernel.data, kernel.getWidth(), kernel.getHeight(), + kernel.getXOrigin(), kernel.getYOrigin(), edgeCond, srcData, src.getWidth(), src + .getHeight(), srcStride, dstData, dst.getWidth(), dst.getHeight(), + dstStride, channels, skipChannel, offsets); + } + + /** + * Ipp filter32f. + * + * @param kernel + * the kernel. + * @param kWidth + * the k width. + * @param kHeight + * the k height. + * @param anchorX + * the anchor x. + * @param anchorY + * the anchor y. + * @param borderType + * the border type. + * @param src + * the src. + * @param srcWidth + * the src width. + * @param srcHeight + * the src height. + * @param srcStride + * the src stride. + * @param dst + * the dst. + * @param dstWidth + * the dst width. + * @param dstHeight + * the dst height. + * @param dstStride + * the dst stride. + * @param channels + * the channels. + * @param skipChannel + * the skip channel. + * @param offsets + * the offsets. + * @return the int. + */ + private native int ippFilter32f(float kernel[], int kWidth, int kHeight, int anchorX, + int anchorY, int borderType, Object src, int srcWidth, int srcHeight, int srcStride, + Object dst, int dstWidth, int dstHeight, int dstStride, int channels, + boolean skipChannel, int offsets[]); +} diff --git a/app/src/main/java/java/awt/image/CropImageFilter.java b/app/src/main/java/java/awt/image/CropImageFilter.java new file mode 100644 index 000000000..2f4ca7813 --- /dev/null +++ b/app/src/main/java/java/awt/image/CropImageFilter.java @@ -0,0 +1,196 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.util.Hashtable; + +/** + * The CropImageFilter class crops a rectangular region of an source Image and + * provides a source for a new image containing the extracted region. + * + * @since Android 1.0 + */ +public class CropImageFilter extends ImageFilter { + + /** + * The HEIGHT. + */ + private final int X, Y, WIDTH, HEIGHT; + + /** + * Instantiates a new CropImageFilter object with the specified rectangular + * area. + * + * @param x + * the X coordinate of rectangular area. + * @param y + * the Y coordinate of rectangular area. + * @param w + * the width of rectangular area. + * @param h + * the height of rectangular area. + */ + public CropImageFilter(int x, int y, int w, int h) { + X = x; + Y = y; + WIDTH = w; + HEIGHT = h; + } + + @SuppressWarnings("unchecked") + @Override + public void setProperties(Hashtable props) { + Hashtable fprops; + if (props == null) { + fprops = new Hashtable(); + } else { + fprops = (Hashtable)props.clone(); + } + String propName = "Crop Filters"; //$NON-NLS-1$ + String prop = "x=" + X + "; y=" + Y + "; width=" + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + WIDTH + "; height=" + HEIGHT; //$NON-NLS-1$ + Object o = fprops.get(propName); + if (o != null) { + if (o instanceof String) { + prop = (String)o + "; " + prop; //$NON-NLS-1$ + } else { + prop = o.toString() + "; " + prop; //$NON-NLS-1$ + } + } + fprops.put(propName, prop); + consumer.setProperties(fprops); + } + + @Override + public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off, + int scansize) { + + if (x + w < X || X + WIDTH < x || y + h < Y || Y + HEIGHT < y) { + return; + } + + int destX, destY, destWidth, destHeight, endX, endY, srcEndX, srcEndY; + + int newOffset = off; + + endX = X + WIDTH; + endY = Y + HEIGHT; + + srcEndX = x + w; + srcEndY = y + h; + + if (x <= X) { + destX = 0; + newOffset += X; + if (endX >= srcEndX) { + destWidth = srcEndX - X; + } else { + destWidth = WIDTH; + } + } else { + destX = x - X; + if (endX >= srcEndX) { + destWidth = w; + } else { + destWidth = endX - x; + } + } + + if (y <= Y) { + newOffset += scansize * (Y - y); + destY = 0; + if (endY >= srcEndY) { + destHeight = srcEndY - Y; + } else { + destHeight = HEIGHT; + } + } else { + destY = y - Y; + if (endY >= srcEndY) { + destHeight = h; + } else { + destHeight = endY - y; + } + } + consumer.setPixels(destX, destY, destWidth, destHeight, model, pixels, newOffset, scansize); + } + + @Override + public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, + int scansize) { + + if (x + w < X || X + WIDTH < x || y + h < Y || Y + HEIGHT < y) { + return; + } + + int destX, destY, destWidth, destHeight, endX, endY, srcEndX, srcEndY; + + int newOffset = off; + + endX = X + WIDTH; + endY = Y + HEIGHT; + + srcEndX = x + w; + srcEndY = y + h; + + if (x <= X) { + destX = 0; + newOffset += X; + if (endX >= srcEndX) { + destWidth = srcEndX - X; + } else { + destWidth = WIDTH; + } + } else { + destX = x - X; + if (endX >= srcEndX) { + destWidth = w; + } else { + destWidth = endX - x; + } + } + + if (y <= Y) { + newOffset += scansize * (Y - y); + destY = 0; + if (endY >= srcEndY) { + destHeight = srcEndY - Y; + } else { + destHeight = HEIGHT; + } + } else { + destY = y - Y; + if (endY >= srcEndY) { + destHeight = h; + } else { + destHeight = endY - y; + } + } + consumer.setPixels(destX, destY, destWidth, destHeight, model, pixels, newOffset, scansize); + } + + @Override + public void setDimensions(int w, int h) { + consumer.setDimensions(WIDTH, HEIGHT); + } + +} diff --git a/app/src/main/java/java/awt/image/DataBuffer.java b/app/src/main/java/java/awt/image/DataBuffer.java index b0884c95a..92f900fd3 100644 --- a/app/src/main/java/java/awt/image/DataBuffer.java +++ b/app/src/main/java/java/awt/image/DataBuffer.java @@ -1,12 +1,481 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + package java.awt.image; -public class DataBuffer { - public static final int TYPE_BYTE = 0; - public static final int TYPE_DOUBLE = 5; - public static final int TYPE_FLOAT = 4; - public static final int TYPE_INT = 3; - public static final int TYPE_SHORT = 2; - public static final int TYPE_UNDEFINED = 32; - public static final int TYPE_USHORT = 1; -} +import org.apache.harmony.awt.gl.image.DataBufferListener; +import org.apache.harmony.awt.internal.nls.Messages; +/** + * The Class DataBuffer is a wrapper class for a data array to be used for the + * situation where a suite of functionality acts on a set of data in a + * consistent way even though the primitive type of the data may vary from one + * use to the next. + * + * @since Android 1.0 + */ +public abstract class DataBuffer { + + /** + * The Constant TYPE_BYTE. + */ + public static final int TYPE_BYTE = 0; + + /** + * The Constant TYPE_USHORT. + */ + public static final int TYPE_USHORT = 1; + + /** + * The Constant TYPE_SHORT. + */ + public static final int TYPE_SHORT = 2; + + /** + * The Constant TYPE_INT. + */ + public static final int TYPE_INT = 3; + + /** + * The Constant TYPE_FLOAT. + */ + public static final int TYPE_FLOAT = 4; + + /** + * The Constant TYPE_DOUBLE. + */ + public static final int TYPE_DOUBLE = 5; + + /** + * The Constant TYPE_UNDEFINED. + */ + public static final int TYPE_UNDEFINED = 32; + + /** + * The data type indicates the primitive type of the data in this + * DataBuffer. + */ + protected int dataType; + + /** + * The number of data arrays in this DataBuffer. + */ + protected int banks; + + /** + * The starting index for reading the data from the first (or only) internal + * data array. + */ + protected int offset; + + /** + * The length (number of elements) of the data arrays. + */ + protected int size; + + /** + * The starting indices for reading the data from the internal data arrays. + */ + protected int offsets[]; + + /** + * The data changed. + */ + boolean dataChanged = true; + + /** + * The data taken. + */ + boolean dataTaken = false; + + /** + * The listener. + */ + DataBufferListener listener; + + static { + AwtImageBackdoorAccessorImpl.init(); + } + + /** + * Instantiates a new data buffer. + * + * @param dataType + * the data type. + * @param size + * the length (number of elements) of the data arrays. + * @param numBanks + * the number of data arrays to create. + * @param offsets + * the starting indices for reading the data from the internal + * data arrays. + */ + protected DataBuffer(int dataType, int size, int numBanks, int[] offsets) { + this.dataType = dataType; + this.size = size; + this.banks = numBanks; + this.offsets = offsets.clone(); + this.offset = offsets[0]; + } + + /** + * Instantiates a new data buffer with all of the data arrays starting at + * the same index. + * + * @param dataType + * the data type. + * @param size + * the length (number of elements) of the data arrays. + * @param numBanks + * the number of data arrays to create. + * @param offset + * the offset to use for all of the data arrays. + */ + protected DataBuffer(int dataType, int size, int numBanks, int offset) { + this.dataType = dataType; + this.size = size; + this.banks = numBanks; + this.offset = offset; + this.offsets = new int[numBanks]; + int i = 0; + while (i < numBanks) { + offsets[i++] = offset; + } + } + + /** + * Instantiates a new data buffer with all of the data arrays read from the + * beginning (at offset zero). + * + * @param dataType + * the data type. + * @param size + * the length (number of elements) of the data arrays. + * @param numBanks + * the number of data arrays to create. + */ + protected DataBuffer(int dataType, int size, int numBanks) { + this.dataType = dataType; + this.size = size; + this.banks = numBanks; + this.offset = 0; + this.offsets = new int[numBanks]; + } + + /** + * Instantiates a new data buffer with one internal data array read from the + * beginning (at offset zero). + * + * @param dataType + * the data type. + * @param size + * the length (number of elements) of the data arrays. + */ + protected DataBuffer(int dataType, int size) { + this.dataType = dataType; + this.size = size; + this.banks = 1; + this.offset = 0; + this.offsets = new int[1]; + } + + /** + * Sets the data value in the specified array at the specified index. + * + * @param bank + * the internal array to the data to. + * @param i + * the index within the array where the data should be written. + * @param val + * the value to write into the array. + */ + public abstract void setElem(int bank, int i, int val); + + /** + * Sets the float data value in the specified array at the specified index. + * + * @param bank + * the internal array to the data to. + * @param i + * the index within the array where the data should be written. + * @param val + * the value to write into the array. + */ + public void setElemFloat(int bank, int i, float val) { + setElem(bank, i, (int)val); + } + + /** + * Sets the double data value in the specified array at the specified index. + * + * @param bank + * the internal array to the data to. + * @param i + * the index within the array where the data should be written. + * @param val + * the value to write into the array. + */ + public void setElemDouble(int bank, int i, double val) { + setElem(bank, i, (int)val); + } + + /** + * Sets the data value in the first array at the specified index. + * + * @param i + * the index within the array where the data should be written. + * @param val + * the value to write into the array. + */ + public void setElem(int i, int val) { + setElem(0, i, val); + } + + /** + * Gets the data value from the specified data array at the specified index. + * + * @param bank + * the data array to read from. + * @param i + * the index within the array where the data should be read. + * @return the data element. + */ + public abstract int getElem(int bank, int i); + + /** + * Gets the float-type data value from the specified data array at the + * specified index. + * + * @param bank + * the data array to read from. + * @param i + * the index within the array where the data should be read. + * @return the data element. + */ + public float getElemFloat(int bank, int i) { + return getElem(bank, i); + } + + /** + * Gets the double-type data value from the specified data array at the + * specified index. + * + * @param bank + * the data array to read from. + * @param i + * the index within the array where the data should be read. + * @return the data element. + */ + public double getElemDouble(int bank, int i) { + return getElem(bank, i); + } + + /** + * Sets the float data value in the first array at the specified index. + * + * @param i + * the index within the array where the data should be written. + * @param val + * the value to write into the array. + */ + public void setElemFloat(int i, float val) { + setElemFloat(0, i, val); + } + + /** + * Sets the double data value in the first array at the specified index. + * + * @param i + * the index within the array where the data should be written. + * @param val + * the value to write into the array. + */ + public void setElemDouble(int i, double val) { + setElemDouble(0, i, val); + } + + /** + * Gets the data value from the first data array at the specified index and + * returns it as an integer. + * + * @param i + * the index within the array where the data should be read. + * @return the data element. + */ + public int getElem(int i) { + return getElem(0, i); + } + + /** + * Gets the data value from the first data array at the specified index and + * returns it as a float. + * + * @param i + * the index within the array where the data should be read. + * @return the data element. + */ + public float getElemFloat(int i) { + return getElem(0, i); + } + + /** + * Gets the data value from the first data array at the specified index and + * returns it as a double. + * + * @param i + * the index within the array where the data should be read. + * @return the data element. + */ + public double getElemDouble(int i) { + return getElem(i); + } + + /** + * Gets the array giving the offsets corresponding to the internal data + * arrays. + * + * @return the array of offsets. + */ + public int[] getOffsets() { + return offsets; + } + + /** + * Gets the size in bits of the primitive data type. + * + * @return the size in bits of the primitive data type. + */ + public int getSize() { + return size; + } + + /** + * Gets the offset corresponding to the first internal data array. + * + * @return the offset. + */ + public int getOffset() { + return offset; + } + + /** + * Gets the number of data arrays in this DataBuffer. + * + * @return the number of data arrays. + */ + public int getNumBanks() { + return banks; + } + + /** + * Gets the primitive type of this buffer's data. + * + * @return the data type. + */ + public int getDataType() { + return this.dataType; + } + + /** + * Gets the size in bits of the primitive data type. + * + * @param type + * the primitive type. + * @return the size in bits of the primitive data type. + */ + public static int getDataTypeSize(int type) { + switch (type) { + + case TYPE_BYTE: + return 8; + + case TYPE_USHORT: + case TYPE_SHORT: + return 16; + + case TYPE_INT: + case TYPE_FLOAT: + return 32; + + case TYPE_DOUBLE: + return 64; + + default: + // awt.22C=Unknown data type {0} + throw new IllegalArgumentException(Messages.getString("awt.22C", type)); //$NON-NLS-1$ + } + } + + /** + * Notifies the listener that the data has changed. + */ + void notifyChanged() { + if (listener != null && !dataChanged) { + dataChanged = true; + listener.dataChanged(); + } + } + + /** + * Notifies the listener that the data has been released. + */ + void notifyTaken() { + if (listener != null && !dataTaken) { + dataTaken = true; + listener.dataTaken(); + } + } + + /** + * Release the data. + */ + void releaseData() { + if (listener != null && dataTaken) { + dataTaken = false; + listener.dataReleased(); + } + } + + /** + * Adds the data buffer listener. + * + * @param listener + * the listener. + */ + void addDataBufferListener(DataBufferListener listener) { + this.listener = listener; + } + + /** + * Removes the data buffer listener. + */ + void removeDataBufferListener() { + listener = null; + } + + /** + * Validate. + */ + void validate() { + dataChanged = false; + } + +} diff --git a/app/src/main/java/java/awt/image/DataBufferByte.java b/app/src/main/java/java/awt/image/DataBufferByte.java new file mode 100644 index 000000000..3407de84d --- /dev/null +++ b/app/src/main/java/java/awt/image/DataBufferByte.java @@ -0,0 +1,183 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +/** + * The Class DataBufferByte is the subclass of DataBuffer for the case where the + * underlying data is of type byte. + * + * @since Android 1.0 + */ +public final class DataBufferByte extends DataBuffer { + + /** + * The data. + */ + byte data[][]; + + /** + * Instantiates a new data buffer of type unsigned short. + * + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. + * @param offsets + * the starting indices for reading the data from the internal + * data arrays. + */ + public DataBufferByte(byte dataArrays[][], int size, int offsets[]) { + super(TYPE_BYTE, size, dataArrays.length, offsets); + data = dataArrays.clone(); + } + + /** + * Instantiates a new data buffer of type unsigned short. + * + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. + */ + public DataBufferByte(byte dataArrays[][], int size) { + super(TYPE_BYTE, size, dataArrays.length); + data = dataArrays.clone(); + } + + /** + * Instantiates a new data buffer of type unsigned short with a single + * underlying array of data. + * + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. + * @param offset + * the starting index to use when reading the data. + */ + public DataBufferByte(byte dataArray[], int size, int offset) { + super(TYPE_BYTE, size, 1, offset); + data = new byte[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new data buffer of type unsigned short with a single + * underlying array of data starting at index 0. + * + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. + */ + public DataBufferByte(byte dataArray[], int size) { + super(TYPE_BYTE, size); + data = new byte[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new empty data buffer of type unsigned short with offsets + * equal to zero. + * + * @param size + * the length (number of elements) to use from the data arrays. + * @param numBanks + * the number of data arrays to create. + */ + public DataBufferByte(int size, int numBanks) { + super(TYPE_BYTE, size, numBanks); + data = new byte[numBanks][]; + int i = 0; + while (i < numBanks) { + data[i++] = new byte[size]; + } + } + + /** + * Instantiates a new empty data buffer of type unsigned short with a single + * underlying array of data starting at index 0. + * + * @param size + * the length (number of elements) to use. + */ + public DataBufferByte(int size) { + super(TYPE_BYTE, size); + data = new byte[1][]; + data[0] = new byte[size]; + } + + @Override + public void setElem(int bank, int i, int val) { + data[bank][offsets[bank] + i] = (byte)val; + notifyChanged(); + } + + @Override + public void setElem(int i, int val) { + data[0][offset + i] = (byte)val; + notifyChanged(); + } + + @Override + public int getElem(int bank, int i) { + return (data[bank][offsets[bank] + i]) & 0xff; + } + + /** + * Gets the data of the specified internal data array. + * + * @param bank + * the index of the desired data array. + * @return the data. + */ + public byte[] getData(int bank) { + notifyTaken(); + return data[bank]; + } + + @Override + public int getElem(int i) { + return (data[0][offset + i]) & 0xff; + } + + /** + * Gets the bank data. + * + * @return the bank data. + */ + public byte[][] getBankData() { + notifyTaken(); + return data.clone(); + } + + /** + * Gets the data of the first data array. + * + * @return the data. + */ + public byte[] getData() { + notifyTaken(); + return data[0]; + } + +} diff --git a/app/src/main/java/java/awt/image/DataBufferDouble.java b/app/src/main/java/java/awt/image/DataBufferDouble.java new file mode 100644 index 000000000..5d0a51688 --- /dev/null +++ b/app/src/main/java/java/awt/image/DataBufferDouble.java @@ -0,0 +1,226 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +/** + * The Class DataBufferDouble is the subclass of DataBuffer for the case where + * the underlying data is of type double. + * + * @since Android 1.0 + */ +public final class DataBufferDouble extends DataBuffer { + + /** + * The data. + */ + double data[][]; + + /** + * Instantiates a new data buffer of type double. + * + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. + * @param offsets + * the starting indices for reading the data from the internal + * data arrays. + */ + public DataBufferDouble(double dataArrays[][], int size, int offsets[]) { + super(TYPE_DOUBLE, size, dataArrays.length, offsets); + data = dataArrays.clone(); + } + + /** + * Instantiates a new data buffer of type double. + * + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. + */ + public DataBufferDouble(double dataArrays[][], int size) { + super(TYPE_DOUBLE, size, dataArrays.length); + data = dataArrays.clone(); + } + + /** + * Instantiates a new data buffer of type double with a single underlying + * array of data. + * + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. + * @param offset + * the starting index to use when reading the data. + */ + public DataBufferDouble(double dataArray[], int size, int offset) { + super(TYPE_DOUBLE, size, 1, offset); + data = new double[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new data buffer of type double with a single underlying + * array of data starting at index 0. + * + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. + */ + public DataBufferDouble(double dataArray[], int size) { + super(TYPE_DOUBLE, size); + data = new double[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new empty data buffer of type double with offsets equal to + * zero. + * + * @param size + * the length (number of elements) to use from the data arrays. + * @param numBanks + * the number of data arrays to create. + */ + public DataBufferDouble(int size, int numBanks) { + super(TYPE_DOUBLE, size, numBanks); + data = new double[numBanks][]; + int i = 0; + while (i < numBanks) { + data[i++] = new double[size]; + } + } + + /** + * Instantiates a new empty data buffer of type double with a single + * underlying array of data starting at index 0. + * + * @param size + * the length (number of elements) to use. + */ + public DataBufferDouble(int size) { + super(TYPE_DOUBLE, size); + data = new double[1][]; + data[0] = new double[size]; + } + + @Override + public void setElem(int bank, int i, int val) { + data[bank][offsets[bank] + i] = val; + notifyChanged(); + } + + @Override + public void setElemFloat(int bank, int i, float val) { + data[bank][offsets[bank] + i] = val; + notifyChanged(); + } + + @Override + public void setElemDouble(int bank, int i, double val) { + data[bank][offsets[bank] + i] = val; + notifyChanged(); + } + + @Override + public void setElem(int i, int val) { + data[0][offset + i] = val; + notifyChanged(); + } + + @Override + public int getElem(int bank, int i) { + return (int)(data[bank][offsets[bank] + i]); + } + + @Override + public float getElemFloat(int bank, int i) { + return (float)(data[bank][offsets[bank] + i]); + } + + @Override + public double getElemDouble(int bank, int i) { + return data[bank][offsets[bank] + i]; + } + + @Override + public void setElemFloat(int i, float val) { + data[0][offset + i] = val; + notifyChanged(); + } + + @Override + public void setElemDouble(int i, double val) { + data[0][offset + i] = val; + notifyChanged(); + } + + /** + * Gets the data of the specified internal data array. + * + * @param bank + * the index of the desired data array. + * @return the data. + */ + public double[] getData(int bank) { + notifyTaken(); + return data[bank]; + } + + @Override + public int getElem(int i) { + return (int)(data[0][offset + i]); + } + + @Override + public float getElemFloat(int i) { + return (float)(data[0][offset + i]); + } + + @Override + public double getElemDouble(int i) { + return data[0][offset + i]; + } + + /** + * Gets the bank data. + * + * @return the bank data. + */ + public double[][] getBankData() { + notifyTaken(); + return data.clone(); + } + + /** + * Gets the data of the first data array. + * + * @return the data. + */ + public double[] getData() { + notifyTaken(); + return data[0]; + } +} diff --git a/app/src/main/java/java/awt/image/DataBufferFloat.java b/app/src/main/java/java/awt/image/DataBufferFloat.java new file mode 100644 index 000000000..9a4a6bfed --- /dev/null +++ b/app/src/main/java/java/awt/image/DataBufferFloat.java @@ -0,0 +1,226 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +/** + * The Class DataBufferFloat is the subclass of DataBuffer for the case where + * the underlying data is float. + * + * @since Android 1.0 + */ +public final class DataBufferFloat extends DataBuffer { + + /** + * The data. + */ + float data[][]; + + /** + * Instantiates a new data buffer of type float. + * + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. + * @param offsets + * the starting indices for reading the data from the internal + * data arrays. + */ + public DataBufferFloat(float dataArrays[][], int size, int offsets[]) { + super(TYPE_FLOAT, size, dataArrays.length, offsets); + data = dataArrays.clone(); + } + + /** + * Instantiates a new data buffer of type float. + * + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. + */ + public DataBufferFloat(float dataArrays[][], int size) { + super(TYPE_FLOAT, size, dataArrays.length); + data = dataArrays.clone(); + } + + /** + * Instantiates a new data buffer of type float with a single underlying + * array of data. + * + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. + * @param offset + * the starting index to use when reading the data. + */ + public DataBufferFloat(float dataArray[], int size, int offset) { + super(TYPE_FLOAT, size, 1, offset); + data = new float[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new data buffer of type float with a single underlying + * array of data starting at index 0. + * + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. + */ + public DataBufferFloat(float dataArray[], int size) { + super(TYPE_FLOAT, size); + data = new float[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new empty data buffer of type float with offsets equal to + * zero. + * + * @param size + * the length (number of elements) to use from the data arrays. + * @param numBanks + * the number of data arrays to create. + */ + public DataBufferFloat(int size, int numBanks) { + super(TYPE_FLOAT, size, numBanks); + data = new float[numBanks][]; + int i = 0; + while (i < numBanks) { + data[i++] = new float[size]; + } + } + + /** + * Instantiates a new empty data buffer of type float with a single + * underlying array of data starting at index 0. + * + * @param size + * the length (number of elements) to use. + */ + public DataBufferFloat(int size) { + super(TYPE_FLOAT, size); + data = new float[1][]; + data[0] = new float[size]; + } + + @Override + public void setElem(int bank, int i, int val) { + data[bank][offsets[bank] + i] = val; + notifyChanged(); + } + + @Override + public void setElemFloat(int bank, int i, float val) { + data[bank][offsets[bank] + i] = val; + notifyChanged(); + } + + @Override + public void setElemDouble(int bank, int i, double val) { + data[bank][offsets[bank] + i] = (float)val; + notifyChanged(); + } + + @Override + public void setElem(int i, int val) { + data[0][offset + i] = val; + notifyChanged(); + } + + @Override + public int getElem(int bank, int i) { + return (int)(data[bank][offsets[bank] + i]); + } + + @Override + public float getElemFloat(int bank, int i) { + return data[bank][offsets[bank] + i]; + } + + @Override + public double getElemDouble(int bank, int i) { + return data[bank][offsets[bank] + i]; + } + + @Override + public void setElemFloat(int i, float val) { + data[0][offset + i] = val; + notifyChanged(); + } + + @Override + public void setElemDouble(int i, double val) { + data[0][offset + i] = (float)val; + notifyChanged(); + } + + /** + * Gets the data of the specified internal data array. + * + * @param bank + * the index of the desired array. + * @return the data. + */ + public float[] getData(int bank) { + notifyTaken(); + return data[bank]; + } + + @Override + public int getElem(int i) { + return (int)(data[0][offset + i]); + } + + @Override + public float getElemFloat(int i) { + return data[0][offset + i]; + } + + @Override + public double getElemDouble(int i) { + return data[0][offset + i]; + } + + /** + * Gets the bank data. + * + * @return the bank data. + */ + public float[][] getBankData() { + notifyTaken(); + return data.clone(); + } + + /** + * Gets the data of the first data array. + * + * @return the data. + */ + public float[] getData() { + notifyTaken(); + return data[0]; + } +} diff --git a/app/src/main/java/java/awt/image/DataBufferInt.java b/app/src/main/java/java/awt/image/DataBufferInt.java index aa5fb73bd..380a1278d 100644 --- a/app/src/main/java/java/awt/image/DataBufferInt.java +++ b/app/src/main/java/java/awt/image/DataBufferInt.java @@ -1,14 +1,182 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + package java.awt.image; -public class DataBufferInt extends DataBuffer { - private int[] array; +/** + * The Class DataBufferInt is the subclass of DataBuffer for the case where the + * underlying data is of type integer. + * + * @since Android 1.0 + */ +public final class DataBufferInt extends DataBuffer { - public DataBufferInt(int[] array, int size) { - this.array = array; + /** + * The data. + */ + int data[][]; + + /** + * Instantiates a new data buffer of type integer. + * + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. + * @param offsets + * the starting indices for reading the data from the internal + * data arrays. + */ + public DataBufferInt(int dataArrays[][], int size, int offsets[]) { + super(TYPE_INT, size, dataArrays.length, offsets); + data = dataArrays.clone(); } + /** + * Instantiates a new data buffer of type integer. + * + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. + */ + public DataBufferInt(int dataArrays[][], int size) { + super(TYPE_INT, size, dataArrays.length); + data = dataArrays.clone(); + } + + /** + * Instantiates a new data buffer of type integer with a single underlying + * array of data. + * + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. + * @param offset + * the starting index to use when reading the data. + */ + public DataBufferInt(int dataArray[], int size, int offset) { + super(TYPE_INT, size, 1, offset); + data = new int[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new data buffer of type integer with a single underlying + * array of data starting at index 0. + * + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. + */ + public DataBufferInt(int dataArray[], int size) { + super(TYPE_INT, size); + data = new int[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new empty data buffer of type integer with offsets equal + * to zero. + * + * @param size + * the length (number of elements) to use from the data arrays. + * @param numBanks + * the number of data arrays to create. + */ + public DataBufferInt(int size, int numBanks) { + super(TYPE_INT, size, numBanks); + data = new int[numBanks][]; + int i = 0; + while (i < numBanks) { + data[i++] = new int[size]; + } + } + + /** + * Instantiates a new empty data buffer of type integer with a single + * underlying array of data starting at index 0. + * + * @param size + * the length (number of elements) to use. + */ + public DataBufferInt(int size) { + super(TYPE_INT, size); + data = new int[1][]; + data[0] = new int[size]; + } + + @Override + public void setElem(int bank, int i, int val) { + data[bank][offsets[bank] + i] = val; + notifyChanged(); + } + + @Override + public void setElem(int i, int val) { + data[0][offset + i] = val; + notifyChanged(); + } + + @Override + public int getElem(int bank, int i) { + return data[bank][offsets[bank] + i]; + } + + /** + * Gets the data of the specified internal data array. + * + * @param bank + * the index of the desired data array. + * @return the data. + */ + public int[] getData(int bank) { + notifyTaken(); + return data[bank]; + } + + @Override + public int getElem(int i) { + return data[0][offset + i]; + } + + /** + * Gets the bank data. + * + * @return the bank data. + */ + public int[][] getBankData() { + notifyTaken(); + return data.clone(); + } + + /** + * Gets the data of the first data array. + * + * @return the data. + */ public int[] getData() { - return this.array; + notifyTaken(); + return data[0]; } } - diff --git a/app/src/main/java/java/awt/image/DataBufferShort.java b/app/src/main/java/java/awt/image/DataBufferShort.java new file mode 100644 index 000000000..1b11b29c3 --- /dev/null +++ b/app/src/main/java/java/awt/image/DataBufferShort.java @@ -0,0 +1,181 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +/** + * The Class DataBufferShort is the subclass of DataBuffer for the case where + * the underlying data is short. + * + * @since Android 1.0 + */ +public final class DataBufferShort extends DataBuffer { + + /** + * The data. + */ + short data[][]; + + /** + * Instantiates a new data buffer of type short. + * + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. + * @param offsets + * the starting indices for reading the data from the internal + * data arrays. + */ + public DataBufferShort(short dataArrays[][], int size, int offsets[]) { + super(TYPE_SHORT, size, dataArrays.length, offsets); + data = dataArrays.clone(); + } + + /** + * Instantiates a new data buffer of type short. + * + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. + */ + public DataBufferShort(short dataArrays[][], int size) { + super(TYPE_SHORT, size, dataArrays.length); + data = dataArrays.clone(); + } + + /** + * Instantiates a new data buffer of type short with a single underlying + * array of data. + * + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. + * @param offset + * the starting index to use when reading the data. + */ + public DataBufferShort(short dataArray[], int size, int offset) { + super(TYPE_SHORT, size, 1, offset); + data = new short[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new data buffer of type short with a single underlying + * array of data starting at index 0. + * + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. + */ + public DataBufferShort(short dataArray[], int size) { + super(TYPE_SHORT, size); + data = new short[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new data buffer of type short with offsets equal to zero. + * + * @param size + * the length (number of elements) to use from the data arrays. + * @param numBanks + * the number of data arrays to create. + */ + public DataBufferShort(int size, int numBanks) { + super(TYPE_SHORT, size, numBanks); + data = new short[numBanks][]; + int i = 0; + while (i < numBanks) { + data[i++] = new short[size]; + } + } + + /** + * Instantiates a new empty data buffer of type short with a single + * underlying array of data starting at index 0. + * + * @param size + * the length (number of elements) to use. + */ + public DataBufferShort(int size) { + super(TYPE_SHORT, size); + data = new short[1][]; + data[0] = new short[size]; + } + + @Override + public void setElem(int bank, int i, int val) { + data[bank][offsets[bank] + i] = (short)val; + notifyChanged(); + } + + @Override + public void setElem(int i, int val) { + data[0][offset + i] = (short)val; + notifyChanged(); + } + + @Override + public int getElem(int bank, int i) { + return (data[bank][offsets[bank] + i]); + } + + /** + * Gets the data of the specified internal data array. + * + * @param bank + * the index of the desired data array. + * @return the data. + */ + public short[] getData(int bank) { + notifyTaken(); + return data[bank]; + } + + @Override + public int getElem(int i) { + return (data[0][offset + i]); + } + + /** + * Gets the bank data. + * + * @return the bank data. + */ + public short[][] getBankData() { + notifyTaken(); + return data.clone(); + } + + /** + * Gets the data of the first data array. + * + * @return the data. + */ + public short[] getData() { + notifyTaken(); + return data[0]; + } +} diff --git a/app/src/main/java/java/awt/image/DataBufferUShort.java b/app/src/main/java/java/awt/image/DataBufferUShort.java new file mode 100644 index 000000000..58d9d8340 --- /dev/null +++ b/app/src/main/java/java/awt/image/DataBufferUShort.java @@ -0,0 +1,195 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Class DataBufferUShort is the subclass of DataBuffer for the case where + * the underlying data is unsigned short. + * + * @since Android 1.0 + */ +public final class DataBufferUShort extends DataBuffer { + + /** + * The data. + */ + short data[][]; + + /** + * Instantiates a new data buffer of type unsigned short. + * + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. + * @param offsets + * the starting indices for reading the data from the internal + * data arrays. + */ + public DataBufferUShort(short dataArrays[][], int size, int offsets[]) { + super(TYPE_USHORT, size, dataArrays.length, offsets); + for (int i = 0; i < dataArrays.length; i++) { + if (dataArrays[i].length < offsets[i] + size) { + // awt.28d=Length of dataArray[{0}] is less than size + + // offset[{1}] + throw new IllegalArgumentException(Messages.getString("awt.28D", i, i)); //$NON-NLS-1$ + } + } + data = dataArrays.clone(); + } + + /** + * Instantiates a new data buffer of type unsigned short. + * + * @param dataArrays + * the data arrays to copy the data from. + * @param size + * the length (number of elements) to use from the data arrays. + */ + public DataBufferUShort(short dataArrays[][], int size) { + super(TYPE_USHORT, size, dataArrays.length); + data = dataArrays.clone(); + } + + /** + * Instantiates a new data buffer of type unsigned short with a single + * underlying array of data. + * + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. + * @param offset + * the starting index to use when reading the data. + */ + public DataBufferUShort(short dataArray[], int size, int offset) { + super(TYPE_USHORT, size, 1, offset); + if (dataArray.length < size + offset) { + // awt.28E=Length of dataArray is less than size + offset + throw new IllegalArgumentException(Messages.getString("awt.28E")); //$NON-NLS-1$ + } + data = new short[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new data buffer of type unsigned short with a single + * underlying array of data starting at index 0. + * + * @param dataArray + * the data array to copy the data from. + * @param size + * the length (number of elements) to use. + */ + public DataBufferUShort(short dataArray[], int size) { + super(TYPE_USHORT, size); + data = new short[1][]; + data[0] = dataArray; + } + + /** + * Instantiates a new empty data buffer of type unsigned short with offsets + * equal to zero. + * + * @param size + * the length (number of elements) to use from the data arrays. + * @param numBanks + * the number of data arrays to create. + */ + public DataBufferUShort(int size, int numBanks) { + super(TYPE_USHORT, size, numBanks); + data = new short[numBanks][]; + int i = 0; + while (i < numBanks) { + data[i++] = new short[size]; + } + } + + /** + * Instantiates a new empty data buffer of type unsigned short with a single + * underlying array of data starting at index 0. + * + * @param size + * the length (number of elements) to use. + */ + public DataBufferUShort(int size) { + super(TYPE_USHORT, size); + data = new short[1][]; + data[0] = new short[size]; + } + + @Override + public void setElem(int bank, int i, int val) { + data[bank][offsets[bank] + i] = (short)val; + notifyChanged(); + } + + @Override + public void setElem(int i, int val) { + data[0][offset + i] = (short)val; + notifyChanged(); + } + + @Override + public int getElem(int bank, int i) { + return (data[bank][offsets[bank] + i]) & 0xffff; + } + + /** + * Gets the data of the specified internal data array. + * + * @param bank + * the index of the desired data array. + * @return the data. + */ + public short[] getData(int bank) { + notifyTaken(); + return data[bank]; + } + + @Override + public int getElem(int i) { + return (data[0][offset + i]) & 0xffff; + } + + /** + * Gets the bank data. + * + * @return the bank data. + */ + public short[][] getBankData() { + notifyTaken(); + return data.clone(); + } + + /** + * Gets the data of the first data array. + * + * @return the data. + */ + public short[] getData() { + notifyTaken(); + return data[0]; + } +} diff --git a/app/src/main/java/java/awt/image/DirectColorModel.java b/app/src/main/java/java/awt/image/DirectColorModel.java new file mode 100644 index 000000000..700eb7a39 --- /dev/null +++ b/app/src/main/java/java/awt/image/DirectColorModel.java @@ -0,0 +1,889 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.awt.color.ColorSpace; +import java.awt.Transparency; +import java.util.Arrays; + +import org.apache.harmony.awt.gl.color.LUTColorConverter; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Class DirectColorModel represents a standard (packed) RGB color model + * with additional support for converting between sRGB color space and 8 or 16 + * bit linear RGB color space using lookup tables. + * + * @since Android 1.0 + */ +public class DirectColorModel extends PackedColorModel { + + /** + * The from_ linea r_ rg b_ lut. + */ + private byte from_LINEAR_RGB_LUT[]; // Lookup table for conversion from + + // Linear RGB Color Space into sRGB + + /** + * The to_ linea r_8 rg b_ lut. + */ + private byte to_LINEAR_8RGB_LUT[]; // Lookup table for conversion from + + // sRGB Color Space into Linear RGB + // 8 bit + + /** + * The to_ linea r_16 rg b_ lut. + */ + private short to_LINEAR_16RGB_LUT[]; // Lookup table for conversion from + + // sRGB Color Space into Linear RGB + // 16 bit + + /** + * The alpha lut. + */ + private byte alphaLUT[]; // Lookup table for scale alpha value + + /** + * The color lu ts. + */ + private byte colorLUTs[][]; // Lookup tables for scale color values + + /** + * The is_s rgb. + */ + private boolean is_sRGB; // ColorModel has sRGB ColorSpace + + /** + * The is_ linea r_ rgb. + */ + private boolean is_LINEAR_RGB; // Color Model has Linear RGB Color + + // Space + + /** + * The LINEA r_ rg b_ length. + */ + private int LINEAR_RGB_Length; // Linear RGB bit length + + /** + * The factor. + */ + private float fFactor; // Scale factor + + /** + * Instantiates a new direct color model. + * + * @param space + * the color space. + * @param bits + * the array of component masks. + * @param rmask + * the bitmask corresponding to the red band. + * @param gmask + * the bitmask corresponding to the green band. + * @param bmask + * the bitmask corresponding to the blue band. + * @param amask + * the bitmask corresponding to the alpha band. + * @param isAlphaPremultiplied + * whether the alpha is pre-multiplied in this color model. + * @param transferType + * the transfer type (primitive java type to use for the + * components). + * @throws IllegalArgumentException + * if the number of bits in the combined bitmasks for the color + * bands is less than one or greater than 32. + */ + public DirectColorModel(ColorSpace space, int bits, int rmask, int gmask, int bmask, int amask, + boolean isAlphaPremultiplied, int transferType) { + + super(space, bits, rmask, gmask, bmask, amask, isAlphaPremultiplied, + (amask == 0 ? Transparency.OPAQUE : Transparency.TRANSLUCENT), transferType); + + initLUTs(); + } + + /** + * Instantiates a new direct color model, determining the transfer type from + * the bits array, the transparency from the alpha mask, and the default + * color space {@link ColorSpace#CS_sRGB}. + * + * @param bits + * the array of component masks. + * @param rmask + * the bitmask corresponding to the red band. + * @param gmask + * the bitmask corresponding to the green band. + * @param bmask + * the bitmask corresponding to the blue band. + * @param amask + * the bitmask corresponding to the alpha band. + */ + public DirectColorModel(int bits, int rmask, int gmask, int bmask, int amask) { + + super(ColorSpace.getInstance(ColorSpace.CS_sRGB), bits, rmask, gmask, bmask, amask, false, + (amask == 0 ? Transparency.OPAQUE : Transparency.TRANSLUCENT), ColorModel + .getTransferType(bits)); + + initLUTs(); + } + + /** + * Instantiates a new direct color model with no alpha channel, determining + * the transfer type from the bits array, the default color space + * {@link ColorSpace#CS_sRGB}, and with the transparency set to + * {@link Transparency#OPAQUE}. + * + * @param bits + * the array of component masks. + * @param rmask + * the bitmask corresponding to the red band. + * @param gmask + * the bitmask corresponding to the green band. + * @param bmask + * the bitmask corresponding to the blue band. + */ + public DirectColorModel(int bits, int rmask, int gmask, int bmask) { + this(bits, rmask, gmask, bmask, 0); + } + + @Override + public Object getDataElements(int components[], int offset, Object obj) { + int pixel = 0; + for (int i = 0; i < numComponents; i++) { + pixel |= (components[offset + i] << offsets[i]) & componentMasks[i]; + } + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[]; + if (obj == null) { + ba = new byte[1]; + } else { + ba = (byte[])obj; + } + ba[0] = (byte)pixel; + obj = ba; + break; + + case DataBuffer.TYPE_USHORT: + short sa[]; + if (obj == null) { + sa = new short[1]; + } else { + sa = (short[])obj; + } + sa[0] = (short)pixel; + obj = sa; + break; + + case DataBuffer.TYPE_INT: + int ia[]; + if (obj == null) { + ia = new int[1]; + } else { + ia = (int[])obj; + } + ia[0] = pixel; + obj = ia; + break; + + default: + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + } + + return obj; + } + + @Override + public Object getDataElements(int rgb, Object pixel) { + if (equals(ColorModel.getRGBdefault())) { + int ia[]; + if (pixel == null) { + ia = new int[1]; + } else { + ia = (int[])pixel; + } + ia[0] = rgb; + return ia; + } + + int alpha = (rgb >> 24) & 0xff; + int red = (rgb >> 16) & 0xff; + int green = (rgb >> 8) & 0xff; + int blue = rgb & 0xff; + + float comp[] = new float[numColorComponents]; + float normComp[] = null; + + if (is_sRGB || is_LINEAR_RGB) { + if (is_LINEAR_RGB) { + if (LINEAR_RGB_Length == 8) { + red = to_LINEAR_8RGB_LUT[red] & 0xff; + green = to_LINEAR_8RGB_LUT[green] & 0xff; + blue = to_LINEAR_8RGB_LUT[blue] & 0xff; + } else { + red = to_LINEAR_16RGB_LUT[red] & 0xffff; + green = to_LINEAR_16RGB_LUT[green] & 0xffff; + blue = to_LINEAR_16RGB_LUT[blue] & 0xffff; + } + } + comp[0] = red / fFactor; + comp[1] = green / fFactor; + comp[2] = blue / fFactor; + if (!hasAlpha) { + normComp = comp; + } else { + float normAlpha = alpha / 255.0f; + normComp = new float[numComponents]; + for (int i = 0; i < numColorComponents; i++) { + normComp[i] = comp[i]; + } + normComp[numColorComponents] = normAlpha; + } + } else { + comp[0] = red / fFactor; + comp[1] = green / fFactor; + comp[2] = blue / fFactor; + float rgbComp[] = cs.fromRGB(comp); + if (!hasAlpha) { + normComp = rgbComp; + } else { + float normAlpha = alpha / 255.0f; + normComp = new float[numComponents]; + for (int i = 0; i < numColorComponents; i++) { + normComp[i] = rgbComp[i]; + } + normComp[numColorComponents] = normAlpha; + } + } + + int pxl = 0; + if (hasAlpha) { + float normAlpha = normComp[numColorComponents]; + alpha = (int)(normAlpha * maxValues[numColorComponents] + 0.5f); + if (isAlphaPremultiplied) { + red = (int)(normComp[0] * normAlpha * maxValues[0] + 0.5f); + green = (int)(normComp[1] * normAlpha * maxValues[1] + 0.5f); + blue = (int)(normComp[2] * normAlpha * maxValues[2] + 0.5f); + } else { + red = (int)(normComp[0] * maxValues[0] + 0.5f); + green = (int)(normComp[1] * maxValues[1] + 0.5f); + blue = (int)(normComp[2] * maxValues[2] + 0.5f); + } + pxl = (alpha << offsets[3]) & componentMasks[3]; + } else { + red = (int)(normComp[0] * maxValues[0] + 0.5f); + green = (int)(normComp[1] * maxValues[1] + 0.5f); + blue = (int)(normComp[2] * maxValues[2] + 0.5f); + } + + pxl |= ((red << offsets[0]) & componentMasks[0]) + | ((green << offsets[1]) & componentMasks[1]) + | ((blue << offsets[2]) & componentMasks[2]); + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[]; + if (pixel == null) { + ba = new byte[1]; + } else { + ba = (byte[])pixel; + } + ba[0] = (byte)pxl; + return ba; + + case DataBuffer.TYPE_USHORT: + short sa[]; + if (pixel == null) { + sa = new short[1]; + } else { + sa = (short[])pixel; + } + sa[0] = (short)pxl; + return sa; + + case DataBuffer.TYPE_INT: + int ia[]; + if (pixel == null) { + ia = new int[1]; + } else { + ia = (int[])pixel; + } + ia[0] = pxl; + return ia; + + default: + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + } + } + + @Override + public final ColorModel coerceData(WritableRaster raster, boolean isAlphaPremultiplied) { + + if (!hasAlpha || this.isAlphaPremultiplied == isAlphaPremultiplied) { + return this; + } + + int minX = raster.getMinX(); + int minY = raster.getMinY(); + int w = raster.getWidth(); + int h = raster.getHeight(); + + int components[] = null; + int transparentComponents[] = new int[numComponents]; + + float alphaFactor = maxValues[numColorComponents]; + + if (isAlphaPremultiplied) { + switch (transferType) { + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_INT: + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + components = raster.getPixel(x, minY, components); + if (components[numColorComponents] == 0) { + raster.setPixel(x, minY, transparentComponents); + } else { + float alpha = components[numColorComponents] / alphaFactor; + for (int n = 0; n < numColorComponents; n++) { + components[n] = (int)(alpha * components[n] + 0.5f); + } + raster.setPixel(x, minY, components); + } + } + + } + break; + + default: + // awt.214=This Color Model doesn't support this + // transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + } + } else { + switch (transferType) { + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_INT: + for (int i = 0; i < h; i++, minY++) { + for (int j = 0, x = minX; j < w; j++, x++) { + components = raster.getPixel(x, minY, components); + if (components[numColorComponents] != 0) { + float alpha = alphaFactor / components[numColorComponents]; + for (int n = 0; n < numColorComponents; n++) { + components[n] = (int)(alpha * components[n] + 0.5f); + } + raster.setPixel(x, minY, components); + } + } + + } + break; + + default: + // awt.214=This Color Model doesn't support this + // transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + } + + } + + return new DirectColorModel(cs, pixel_bits, componentMasks[0], componentMasks[1], + componentMasks[2], componentMasks[3], isAlphaPremultiplied, transferType); + } + + @Override + public String toString() { + // The output format based on 1.5 release behaviour. + // It could be reveled such way: + // BufferedImage bi = new BufferedImage(1, 1, + // BufferedImage.TYPE_INT_ARGB); + // ColorModel cm = bi.getColorModel(); + // System.out.println(cm.toString()); + String str = "DirectColorModel:" + " rmask = " + //$NON-NLS-1$ //$NON-NLS-2$ + Integer.toHexString(componentMasks[0]) + " gmask = " + //$NON-NLS-1$ + Integer.toHexString(componentMasks[1]) + " bmask = " + //$NON-NLS-1$ + Integer.toHexString(componentMasks[2]) + " amask = " + //$NON-NLS-1$ + (!hasAlpha ? "0" : Integer.toHexString(componentMasks[3])); //$NON-NLS-1$ + + return str; + } + + @Override + public final int[] getComponents(Object pixel, int components[], int offset) { + + if (components == null) { + components = new int[numComponents + offset]; + } + + int intPixel = 0; + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[])pixel; + intPixel = ba[0] & 0xff; + break; + + case DataBuffer.TYPE_USHORT: + short sa[] = (short[])pixel; + intPixel = sa[0] & 0xffff; + break; + + case DataBuffer.TYPE_INT: + int ia[] = (int[])pixel; + intPixel = ia[0]; + break; + + default: + // awt.22D=This transferType ( {0} ) is not supported by this + // color model + throw new UnsupportedOperationException(Messages.getString("awt.22D", //$NON-NLS-1$ + transferType)); + } + + return getComponents(intPixel, components, offset); + } + + @Override + public int getRed(Object inData) { + int pixel = 0; + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[])inData; + pixel = ba[0] & 0xff; + break; + + case DataBuffer.TYPE_USHORT: + short sa[] = (short[])inData; + pixel = sa[0] & 0xffff; + break; + + case DataBuffer.TYPE_INT: + int ia[] = (int[])inData; + pixel = ia[0]; + break; + + default: + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + } + return getRed(pixel); + } + + @Override + public int getRGB(Object inData) { + int pixel = 0; + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[])inData; + pixel = ba[0] & 0xff; + break; + + case DataBuffer.TYPE_USHORT: + short sa[] = (short[])inData; + pixel = sa[0] & 0xffff; + break; + + case DataBuffer.TYPE_INT: + int ia[] = (int[])inData; + pixel = ia[0]; + break; + + default: + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + } + return getRGB(pixel); + } + + @Override + public int getGreen(Object inData) { + int pixel = 0; + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[])inData; + pixel = ba[0] & 0xff; + break; + + case DataBuffer.TYPE_USHORT: + short sa[] = (short[])inData; + pixel = sa[0] & 0xffff; + break; + + case DataBuffer.TYPE_INT: + int ia[] = (int[])inData; + pixel = ia[0]; + break; + + default: + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + } + return getGreen(pixel); + } + + @Override + public int getBlue(Object inData) { + int pixel = 0; + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[])inData; + pixel = ba[0] & 0xff; + break; + + case DataBuffer.TYPE_USHORT: + short sa[] = (short[])inData; + pixel = sa[0] & 0xffff; + break; + + case DataBuffer.TYPE_INT: + int ia[] = (int[])inData; + pixel = ia[0]; + break; + + default: + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + } + return getBlue(pixel); + } + + @Override + public int getAlpha(Object inData) { + int pixel = 0; + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[])inData; + pixel = ba[0] & 0xff; + break; + + case DataBuffer.TYPE_USHORT: + short sa[] = (short[])inData; + pixel = sa[0] & 0xffff; + break; + + case DataBuffer.TYPE_INT: + int ia[] = (int[])inData; + pixel = ia[0]; + break; + + default: + // awt.214=This Color Model doesn't support this transferType + throw new UnsupportedOperationException(Messages.getString("awt.214")); //$NON-NLS-1$ + } + return getAlpha(pixel); + } + + @Override + public final WritableRaster createCompatibleWritableRaster(int w, int h) { + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new IllegalArgumentException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + int bandMasks[] = componentMasks.clone(); + + if (pixel_bits > 16) { + return Raster.createPackedRaster(DataBuffer.TYPE_INT, w, h, bandMasks, null); + } else if (pixel_bits > 8) { + return Raster.createPackedRaster(DataBuffer.TYPE_USHORT, w, h, bandMasks, null); + } else { + return Raster.createPackedRaster(DataBuffer.TYPE_BYTE, w, h, bandMasks, null); + } + } + + @Override + public boolean isCompatibleRaster(Raster raster) { + SampleModel sm = raster.getSampleModel(); + if (!(sm instanceof SinglePixelPackedSampleModel)) { + return false; + } + + SinglePixelPackedSampleModel sppsm = (SinglePixelPackedSampleModel)sm; + + if (sppsm.getNumBands() != numComponents) { + return false; + } + if (raster.getTransferType() != transferType) { + return false; + } + + int maskBands[] = sppsm.getBitMasks(); + return Arrays.equals(maskBands, componentMasks); + } + + @Override + public int getDataElement(int components[], int offset) { + int pixel = 0; + for (int i = 0; i < numComponents; i++) { + pixel |= (components[offset + i] << offsets[i]) & componentMasks[i]; + } + return pixel; + } + + @Override + public final int[] getComponents(int pixel, int components[], int offset) { + if (components == null) { + components = new int[numComponents + offset]; + } + for (int i = 0; i < numComponents; i++) { + components[offset + i] = (pixel & componentMasks[i]) >> offsets[i]; + } + return components; + } + + @Override + public final int getRed(int pixel) { + if (is_sRGB) { + return getComponentFrom_sRGB(pixel, 0); + } + if (is_LINEAR_RGB) { + return getComponentFrom_LINEAR_RGB(pixel, 0); + } + return getComponentFrom_RGB(pixel, 0); + } + + @Override + public final int getRGB(int pixel) { + return (getAlpha(pixel) << 24) | (getRed(pixel) << 16) | (getGreen(pixel) << 8) + | getBlue(pixel); + } + + @Override + public final int getGreen(int pixel) { + if (is_sRGB) { + return getComponentFrom_sRGB(pixel, 1); + } + if (is_LINEAR_RGB) { + return getComponentFrom_LINEAR_RGB(pixel, 1); + } + return getComponentFrom_RGB(pixel, 1); + } + + @Override + public final int getBlue(int pixel) { + if (is_sRGB) { + return getComponentFrom_sRGB(pixel, 2); + } + if (is_LINEAR_RGB) { + return getComponentFrom_LINEAR_RGB(pixel, 2); + } + return getComponentFrom_RGB(pixel, 2); + } + + @Override + public final int getAlpha(int pixel) { + if (!hasAlpha) { + return 255; + } + int a = (pixel & componentMasks[3]) >>> offsets[3]; + if (bits[3] == 8) { + return a; + } + return alphaLUT[a] & 0xff; + } + + /** + * Gets the red mask. + * + * @return the red mask. + */ + public final int getRedMask() { + return componentMasks[0]; + } + + /** + * Gets the green mask. + * + * @return the green mask. + */ + public final int getGreenMask() { + return componentMasks[1]; + } + + /** + * Gets the blue mask. + * + * @return the blue mask. + */ + public final int getBlueMask() { + return componentMasks[2]; + } + + /** + * Gets the alpha mask. + * + * @return the alpha mask. + */ + public final int getAlphaMask() { + if (hasAlpha) { + return componentMasks[3]; + } + return 0; + } + + /** + * Initialization of Lookup tables. + */ + private void initLUTs() { + is_sRGB = cs.isCS_sRGB(); + is_LINEAR_RGB = (cs == LUTColorConverter.LINEAR_RGB_CS); + + if (is_LINEAR_RGB) { + if (maxBitLength > 8) { + LINEAR_RGB_Length = 16; + from_LINEAR_RGB_LUT = LUTColorConverter.getFrom16lRGBtosRGB_LUT(); + to_LINEAR_16RGB_LUT = LUTColorConverter.getFromsRGBto16lRGB_LUT(); + } else { + LINEAR_RGB_Length = 8; + from_LINEAR_RGB_LUT = LUTColorConverter.getFrom8lRGBtosRGB_LUT(); + to_LINEAR_8RGB_LUT = LUTColorConverter.getFromsRGBto8lRGB_LUT(); + } + fFactor = ((1 << LINEAR_RGB_Length) - 1); + } else { + fFactor = 255.0f; + } + + if (hasAlpha && bits[3] != 8) { + alphaLUT = new byte[maxValues[3] + 1]; + for (int i = 0; i <= maxValues[3]; i++) { + alphaLUT[i] = (byte)(scales[3] * i + 0.5f); + } + + } + + if (!isAlphaPremultiplied) { + colorLUTs = new byte[3][]; + + if (is_sRGB) { + for (int i = 0; i < numColorComponents; i++) { + if (bits[i] != 8) { + for (int j = 0; j < i; j++) { + if (bits[i] == bits[j]) { + colorLUTs[i] = colorLUTs[j]; + break; + } + } + colorLUTs[i] = new byte[maxValues[i] + 1]; + for (int j = 0; j <= maxValues[i]; j++) { + colorLUTs[i][j] = (byte)(scales[i] * j + 0.5f); + } + } + } + } + + if (is_LINEAR_RGB) { + for (int i = 0; i < numColorComponents; i++) { + if (bits[i] != LINEAR_RGB_Length) { + for (int j = 0; j < i; j++) { + if (bits[i] == bits[j]) { + colorLUTs[i] = colorLUTs[j]; + break; + } + } + colorLUTs[i] = new byte[maxValues[i] + 1]; + for (int j = 0; j <= maxValues[0]; j++) { + int idx; + if (LINEAR_RGB_Length == 8) { + idx = (int)(scales[i] * j + 0.5f); + } else { + idx = (int)(scales[i] * j * 257.0f + 0.5f); + } + colorLUTs[i][j] = from_LINEAR_RGB_LUT[idx]; + } + } + } + } + + } + } + + /** + * This method return RGB component value if Color Model has sRGB + * ColorSpace. + * + * @param pixel + * the integer representation of the pixel. + * @param idx + * the index of the pixel component. + * @return the value of the pixel component scaled from 0 to 255. + */ + private int getComponentFrom_sRGB(int pixel, int idx) { + int comp = (pixel & componentMasks[idx]) >> offsets[idx]; + if (isAlphaPremultiplied) { + int alpha = (pixel & componentMasks[3]) >>> offsets[3]; + comp = alpha == 0 ? 0 : (int)(scales[idx] * comp * 255.0f / (scales[3] * alpha) + 0.5f); + } else if (bits[idx] != 8) { + comp = colorLUTs[idx][comp] & 0xff; + } + return comp; + } + + /** + * This method return RGB component value if Color Model has Linear RGB + * ColorSpace. + * + * @param pixel + * the integer representation of the pixel. + * @param idx + * the index of the pixel component. + * @return the value of the pixel component scaled from 0 to 255. + */ + private int getComponentFrom_LINEAR_RGB(int pixel, int idx) { + int comp = (pixel & componentMasks[idx]) >> offsets[idx]; + if (isAlphaPremultiplied) { + float factor = ((1 << LINEAR_RGB_Length) - 1); + int alpha = (pixel & componentMasks[3]) >> offsets[3]; + comp = alpha == 0 ? 0 : (int)(scales[idx] * comp * factor / (scales[3] * alpha) + 0.5f); + } else if (bits[idx] != LINEAR_RGB_Length) { + comp = colorLUTs[idx][comp] & 0xff; + } else { + comp = from_LINEAR_RGB_LUT[comp] & 0xff; + } + return comp; + } + + /** + * This method return RGB component value if Color Model has arbitrary RGB + * ColorSapce. + * + * @param pixel + * the integer representation of the pixel. + * @param idx + * the index of the pixel component. + * @return the value of the pixel component scaled from 0 to 255. + */ + private int getComponentFrom_RGB(int pixel, int idx) { + int components[] = getComponents(pixel, null, 0); + float[] normComponents = getNormalizedComponents(components, 0, null, 0); + float[] sRGBcomponents = cs.toRGB(normComponents); + return (int)(sRGBcomponents[idx] * 255.0f + 0.5f); + } + +} diff --git a/app/src/main/java/java/awt/image/FilteredImageSource.java b/app/src/main/java/java/awt/image/FilteredImageSource.java new file mode 100644 index 000000000..ed8558d3c --- /dev/null +++ b/app/src/main/java/java/awt/image/FilteredImageSource.java @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.util.Hashtable; + +/** + * The FilteredImageSource class is used for producing image data for a new + * filtered version of the original image using the specified filter object. + * + * @since Android 1.0 + */ +public class FilteredImageSource implements ImageProducer { + + /** + * The source. + */ + private final ImageProducer source; + + /** + * The filter. + */ + private final ImageFilter filter; + + /** + * The cons table. + */ + private final Hashtable consTable = new Hashtable(); + + /** + * Instantiates a new FilteredImageSource object with the specified + * ImageProducer and the ImageFilter objects. + * + * @param orig + * the specified ImageProducer. + * @param imgf + * the specified ImageFilter. + */ + public FilteredImageSource(ImageProducer orig, ImageFilter imgf) { + source = orig; + filter = imgf; + } + + public synchronized boolean isConsumer(ImageConsumer ic) { + if (ic != null) { + return consTable.containsKey(ic); + } + return false; + } + + public void startProduction(ImageConsumer ic) { + addConsumer(ic); + ImageConsumer fic = consTable.get(ic); + source.startProduction(fic); + } + + public void requestTopDownLeftRightResend(ImageConsumer ic) { + if (ic != null && isConsumer(ic)) { + ImageFilter fic = (ImageFilter)consTable.get(ic); + fic.resendTopDownLeftRight(source); + } + } + + public synchronized void removeConsumer(ImageConsumer ic) { + if (ic != null && isConsumer(ic)) { + ImageConsumer fic = consTable.get(ic); + source.removeConsumer(fic); + consTable.remove(ic); + } + } + + public synchronized void addConsumer(ImageConsumer ic) { + if (ic != null && !isConsumer(ic)) { + ImageConsumer fic = filter.getFilterInstance(ic); + source.addConsumer(fic); + consTable.put(ic, fic); + } + } +} diff --git a/app/src/main/java/java/awt/image/ImageConsumer.java b/app/src/main/java/java/awt/image/ImageConsumer.java new file mode 100644 index 000000000..caf87d108 --- /dev/null +++ b/app/src/main/java/java/awt/image/ImageConsumer.java @@ -0,0 +1,185 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.util.Hashtable; + +/** + * The ImageConsumer interface provides the data about the image and about how + * its data is delivered. A ImageProducer provides all of the information about + * the image using the methods defined in this interface. + * + * @since Android 1.0 + */ +public interface ImageConsumer { + + /** + * The Constant RANDOMPIXELORDER indicates that the pixels are delivered in + * a random order. + */ + public static final int RANDOMPIXELORDER = 1; + + /** + * The Constant TOPDOWNLEFTRIGHT indicates that the pixels are delivered in + * top-down, left-to-right order. + */ + public static final int TOPDOWNLEFTRIGHT = 2; + + /** + * The Constant COMPLETESCANLINES indicates that the pixels are delivered in + * complete scanline. + */ + public static final int COMPLETESCANLINES = 4; + + /** + * The Constant SINGLEPASS indicates that pixels are delivered in a single + * pass. + */ + public static final int SINGLEPASS = 8; + + /** + * The Constant SINGLEFRAME indicates that image consists of single frame. + */ + public static final int SINGLEFRAME = 16; + + /** + * The Constant IMAGEERROR indicates an image error during image producing. + */ + public static final int IMAGEERROR = 1; + + /** + * The Constant SINGLEFRAMEDONE indicates that only one of the image's + * frames is completed. + */ + public static final int SINGLEFRAMEDONE = 2; + + /** + * The Constant STATICIMAGEDONE indicates that the image is completed. + */ + public static final int STATICIMAGEDONE = 3; + + /** + * The Constant IMAGEABORTED indicates that the image producing process is + * aborted. + */ + public static final int IMAGEABORTED = 4; + + /** + * Sets the properties for the image associated with this ImageConsumer. + * + * @param props + * the properties for the image associated with this + * ImageConsumer. + */ + public void setProperties(Hashtable props); + + /** + * Sets the ColorModel object. + * + * @param model + * the new ColorModel. + */ + public void setColorModel(ColorModel model); + + /** + * Sets the pixels for the specified rectangular area of the image. + * + * @param x + * the X coordinate of rectangular area. + * @param y + * the Y coordinate of rectangular area. + * @param w + * the width of rectangular area. + * @param h + * the height of rectangular area. + * @param model + * the specified ColorModel to be used for pixels converting. + * @param pixels + * the array of pixels. + * @param off + * the offset of pixels array. + * @param scansize + * the distance from the one row of pixels to the next row in the + * specified array. + */ + public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off, + int scansize); + + /** + * Sets the pixels for the specified rectangular area of the image. + * + * @param x + * the X coordinate of rectangular area. + * @param y + * the Y coordinate of rectangular area. + * @param w + * the width of rectangular area. + * @param h + * the height of rectangular area. + * @param model + * the specified ColorModel to be used for pixels converting. + * @param pixels + * the array of pixels. + * @param off + * the offset of pixels array. + * @param scansize + * the distance from the one row of pixels to the next row in the + * specified array. + */ + public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, + int scansize); + + /** + * Sets the dimensions of a source image. + * + * @param width + * the width of the image. + * @param height + * the height of the image. + */ + public void setDimensions(int width, int height); + + /** + * Sets the hint flags of pixels order, which is used by the ImageConsumer + * for obtaining pixels from the ImageProducer for which this ImageConsumer + * is added. + * + * @param hintflags + * the mask of hint flags. + */ + public void setHints(int hintflags); + + /** + * THis method is called in the one of the following cases: + *

    + *
  • The ImageProducer (for which this ImageConsumer is added) has been + * delivered all pixels of the source image.
  • + *
  • A one frame of an animation has been completed.
  • + *
  • An error while loading or producing of the image has occurred. + *
+ * + * @param status + * the status of image producing. + */ + public void imageComplete(int status); + +} diff --git a/app/src/main/java/java/awt/image/ImageFilter.java b/app/src/main/java/java/awt/image/ImageFilter.java new file mode 100644 index 000000000..d2c9f5024 --- /dev/null +++ b/app/src/main/java/java/awt/image/ImageFilter.java @@ -0,0 +1,134 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.util.Hashtable; + +/** + * The ImageFilter class provides a filter for delivering image data from an + * ImageProducer to an ImageConsumer. + * + * @since Android 1.0 + */ +public class ImageFilter implements ImageConsumer, Cloneable { + + /** + * The consumer. + */ + protected ImageConsumer consumer; + + /** + * Instantiates a new ImageFilter. + */ + public ImageFilter() { + super(); + } + + /** + * Gets an instance of an ImageFilter object which performs the filtering + * for the specified ImageConsumer. + * + * @param ic + * the specified ImageConsumer. + * @return an ImageFilter used to perform the filtering for the specified + * ImageConsumer. + */ + public ImageFilter getFilterInstance(ImageConsumer ic) { + ImageFilter filter = (ImageFilter)clone(); + filter.consumer = ic; + return filter; + } + + @SuppressWarnings("unchecked") + public void setProperties(Hashtable props) { + Hashtable fprops; + if (props == null) { + fprops = new Hashtable(); + } else { + fprops = (Hashtable)props.clone(); + } + String propName = "Filters"; //$NON-NLS-1$ + String prop = "Null filter"; //$NON-NLS-1$ + Object o = fprops.get(propName); + if (o != null) { + if (o instanceof String) { + prop = (String)o + "; " + prop; //$NON-NLS-1$ + } else { + prop = o.toString() + "; " + prop; //$NON-NLS-1$ + } + } + fprops.put(propName, prop); + consumer.setProperties(fprops); + } + + /** + * Returns a copy of this ImageFilter. + * + * @return a copy of this ImageFilter. + */ + @Override + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + return null; + } + } + + /** + * Responds to a request for a Top-Down-Left-Right ordered resend of the + * pixel data from an ImageConsumer. + * + * @param ip + * the ImageProducer that provides this instance of the filter. + */ + public void resendTopDownLeftRight(ImageProducer ip) { + ip.requestTopDownLeftRightResend(this); + } + + public void setColorModel(ColorModel model) { + consumer.setColorModel(model); + } + + public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off, + int scansize) { + consumer.setPixels(x, y, w, h, model, pixels, off, scansize); + } + + public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, + int scansize) { + consumer.setPixels(x, y, w, h, model, pixels, off, scansize); + } + + public void setDimensions(int width, int height) { + consumer.setDimensions(width, height); + } + + public void setHints(int hints) { + consumer.setHints(hints); + } + + public void imageComplete(int status) { + consumer.imageComplete(status); + } + +} diff --git a/app/src/main/java/java/awt/image/ImageObserver.java b/app/src/main/java/java/awt/image/ImageObserver.java index 556003b52..21ec41bf2 100644 --- a/app/src/main/java/java/awt/image/ImageObserver.java +++ b/app/src/main/java/java/awt/image/ImageObserver.java @@ -1,5 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + package java.awt.image; -public class ImageObserver -{ -} \ No newline at end of file +import java.awt.Image; + +/** + * the ImageObserver interface is an asynchronous update interface for receiving + * notifications about Image construction status. + * + * @since Android 1.0 + */ +public interface ImageObserver { + + /** + * The Constant WIDTH indicates that the width of the image is available. + */ + public static final int WIDTH = 1; + + /** + * The Constant HEIGHT indicates that the width of the image is available. + */ + public static final int HEIGHT = 2; + + /** + * The Constant PROPERTIES indicates that the properties of the image are + * available. + */ + public static final int PROPERTIES = 4; + + /** + * The Constant SOMEBITS indicates that more bits needed for drawing a + * scaled variation of the image pixels are available. + */ + public static final int SOMEBITS = 8; + + /** + * The Constant FRAMEBITS indicates that complete frame of a image which was + * previously drawn is now available for drawing again. + */ + public static final int FRAMEBITS = 16; + + /** + * The Constant ALLBITS indicates that an image which was previously drawn + * is now complete and can be drawn again. + */ + public static final int ALLBITS = 32; + + /** + * The Constant ERROR indicates that error occurred. + */ + public static final int ERROR = 64; + + /** + * The Constant ABORT indicates that the image producing is aborted. + */ + public static final int ABORT = 128; + + /** + * This method is called when information about an Image interface becomes + * available. This method returns true if further updates are needed, false + * if not. + * + * @param img + * the image to be observed. + * @param infoflags + * the bitwise OR combination of information flags: ABORT, + * ALLBITS, ERROR, FRAMEBITS, HEIGHT, PROPERTIES, SOMEBITS, + * WIDTH. + * @param x + * the X coordinate. + * @param y + * the Y coordinate. + * @param width + * the width. + * @param height + * the height. + * @return true if further updates are needed, false if not. + */ + public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height); + +} diff --git a/app/src/main/java/java/awt/image/ImageProducer.java b/app/src/main/java/java/awt/image/ImageProducer.java new file mode 100644 index 000000000..9138be271 --- /dev/null +++ b/app/src/main/java/java/awt/image/ImageProducer.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +/** + * The ImageProducer provides an interface for objects which produce the image + * data. ImageProducer is used for reconstructing the image. Each image contains + * an ImageProducer. + * + * @since Android 1.0 + */ +public interface ImageProducer { + + /** + * Checks if the specified ImageConsumer is registered with this + * ImageProvider or not. + * + * @param ic + * the ImageConsumer to be checked. + * @return true, if the specified ImageConsumer is registered with this + * ImageProvider, false otherwise. + */ + public boolean isConsumer(ImageConsumer ic); + + /** + * Starts a reconstruction of the image data which will be delivered to this + * consumer. This method adds the specified ImageConsumer before + * reconstructing the image. + * + * @param ic + * the specified ImageConsumer. + */ + public void startProduction(ImageConsumer ic); + + /** + * Requests the ImageProducer to resend the image data in + * ImageConsumer.TOPDOWNLEFTRIGHT order. + * + * @param ic + * the specified ImageConsumer. + */ + public void requestTopDownLeftRightResend(ImageConsumer ic); + + /** + * Deregisters the specified ImageConsumer. + * + * @param ic + * the specified ImageConsumer. + */ + public void removeConsumer(ImageConsumer ic); + + /** + * Adds the specified ImageConsumer object to this ImageProducer. + * + * @param ic + * the specified ImageConsumer. + */ + public void addConsumer(ImageConsumer ic); + +} diff --git a/app/src/main/java/java/awt/image/ImagingOpException.java b/app/src/main/java/java/awt/image/ImagingOpException.java new file mode 100644 index 000000000..e0c0127f4 --- /dev/null +++ b/app/src/main/java/java/awt/image/ImagingOpException.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + * + * @date: Oct 5, 2005 + */ + +package java.awt.image; + +/** + * The ImagingOpException class provides error notification when the + * BufferedImageOp or RasterOp filter methods can not perform the desired filter + * operation. + * + * @since Android 1.0 + */ +public class ImagingOpException extends RuntimeException { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = 8026288481846276658L; + + /** + * Instantiates a new ImagingOpException with a detail message. + * + * @param s + * the detail message. + */ + public ImagingOpException(String s) { + super(s); + } +} diff --git a/app/src/main/java/java/awt/image/IndexColorModel.java b/app/src/main/java/java/awt/image/IndexColorModel.java new file mode 100644 index 000000000..c320eacc6 --- /dev/null +++ b/app/src/main/java/java/awt/image/IndexColorModel.java @@ -0,0 +1,1080 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.awt.Transparency; +import java.awt.color.ColorSpace; +import java.math.BigInteger; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Class IndexColorModel represents a color model in which the color values + * of the pixels are read from a palette. + * + * @since Android 1.0 + */ +public class IndexColorModel extends ColorModel { + + /** + * The color map. + */ + private int colorMap[]; // Color Map + + /** + * The map size. + */ + private int mapSize; // Color Map size + + /** + * The transparent index. + */ + private int transparentIndex; // Index of fully transparent pixel + + /** + * The gray palette. + */ + private boolean grayPalette; // Color Model has Color Map with Gray Pallete + + /** + * The valid bits. + */ + private BigInteger validBits; // Specify valid Color Map values + + /** + * The Constant CACHESIZE. + */ + private static final int CACHESIZE = 20; // Cache size. Cache used for + + // improving performace of selection + // nearest color in Color Map + + /** + * The cachetable. + */ + private final int cachetable[] = new int[CACHESIZE * 2]; // Cache table - + + // used for + + // storing RGB values and that appropriate indices + // in the Color Map + + /** + * The next insert idx. + */ + private int nextInsertIdx = 0; // Next index for insertion into Cache table + + /** + * The total inserted. + */ + private int totalInserted = 0; // Number of inserted values into Cache table + + /** + * Instantiates a new index color model. + * + * @param bits + * the array of component masks. + * @param size + * the size of the color map. + * @param cmap + * the array that gives the color mapping. + * @param start + * the start index of the color mapping data within the cmap + * array. + * @param transferType + * the transfer type (primitive java type to use for the + * components). + * @param validBits + * a list of which bits represent valid colormap values, or null + * if all are valid. + * @throws IllegalArgumentException + * if the size of the color map is less than one. + */ + public IndexColorModel(int bits, int size, int cmap[], int start, int transferType, + BigInteger validBits) { + + super(bits, IndexColorModel.createBits(true), ColorSpace.getInstance(ColorSpace.CS_sRGB), + true, false, Transparency.OPAQUE, validateTransferType(transferType)); + + if (size < 1) { + // awt.264=Size of the color map is less than 1 + throw new IllegalArgumentException(Messages.getString("awt.264")); //$NON-NLS-1$ + } + + mapSize = size; + colorMap = new int[mapSize]; + transparentIndex = -1; + + if (validBits != null) { + for (int i = 0; i < mapSize; i++) { + if (!validBits.testBit(i)) { + this.validBits = validBits; + } + break; + } + } + + transparency = Transparency.OPAQUE; + int alphaMask = 0xff000000; + int alpha = 0; + + for (int i = 0; i < mapSize; i++, start++) { + colorMap[i] = cmap[start]; + alpha = cmap[start] & alphaMask; + + if (alpha == alphaMask) { + continue; + } + if (alpha == 0) { + if (transparentIndex < 0) { + transparentIndex = i; + } + if (transparency == Transparency.OPAQUE) { + transparency = Transparency.BITMASK; + } + } else if (alpha != alphaMask && transparency != Transparency.TRANSLUCENT) { + transparency = Transparency.TRANSLUCENT; + } + + } + checkPalette(); + + } + + /** + * Instantiates a new index color model. + * + * @param bits + * the array of component masks. + * @param size + * the size of the color map. + * @param cmap + * the array that gives the color mapping. + * @param start + * the start index of the color mapping data within the cmap + * array. + * @param hasalpha + * whether this color model uses alpha. + * @param trans + * the transparency supported, @see java.awt.Transparency. + * @param transferType + * the transfer type (primitive java type to use for the + * components). + * @throws IllegalArgumentException + * if the size of the color map is less than one. + */ + public IndexColorModel(int bits, int size, int cmap[], int start, boolean hasalpha, int trans, + int transferType) { + + super(bits, IndexColorModel.createBits(hasalpha || (trans >= 0)), ColorSpace + .getInstance(ColorSpace.CS_sRGB), (hasalpha || (trans >= 0)), false, + Transparency.OPAQUE, validateTransferType(transferType)); + + if (size < 1) { + // awt.264=Size of the color map is less than 1 + throw new IllegalArgumentException(Messages.getString("awt.264")); //$NON-NLS-1$ + } + + mapSize = size; + colorMap = new int[mapSize]; + if (trans >= 0 && trans < mapSize) { + transparentIndex = trans; + transparency = Transparency.BITMASK; + } else { + transparentIndex = -1; + transparency = Transparency.OPAQUE; + } + + int alphaMask = 0xff000000; + int alpha = 0; + + for (int i = 0; i < mapSize; i++, start++) { + if (transparentIndex == i) { + colorMap[i] = cmap[start] & 0x00ffffff; + continue; + } + if (hasalpha) { + alpha = cmap[start] & alphaMask; + colorMap[i] = cmap[start]; + + if (alpha == alphaMask) { + continue; + } + if (alpha == 0) { + if (trans < 0) { + trans = i; + } + if (transparency == Transparency.OPAQUE) { + transparency = Transparency.BITMASK; + } + } else if (alpha != 0 && transparency != Transparency.TRANSLUCENT) { + transparency = Transparency.TRANSLUCENT; + } + } else { + colorMap[i] = alphaMask | cmap[start]; + } + } + checkPalette(); + + } + + /** + * Instantiates a new index color model by building the color map from + * arrays of red, green, blue, and alpha values. + * + * @param bits + * the array of component masks. + * @param size + * the size of the color map. + * @param r + * the array giving the red components of the entries in the + * color map. + * @param g + * the array giving the green components of the entries in the + * color map. + * @param b + * the array giving the blue components of the entries in the + * color map. + * @param a + * the array giving the alpha components of the entries in the + * color map. + * @throws IllegalArgumentException + * if the size of the color map is less than one. + * @throws ArrayIndexOutOfBoundsException + * if the size of one of the component arrays is less than the + * size of the color map. + */ + public IndexColorModel(int bits, int size, byte r[], byte g[], byte b[], byte a[]) { + + super(bits, IndexColorModel.createBits(true), ColorSpace.getInstance(ColorSpace.CS_sRGB), + true, false, Transparency.OPAQUE, validateTransferType(ColorModel + .getTransferType(bits))); + + createColorMap(size, r, g, b, a, -1); + checkPalette(); + } + + /** + * Instantiates a new index color model by building the color map from + * arrays of red, green, and blue values. + * + * @param bits + * the array of component masks. + * @param size + * the size of the color map. + * @param r + * the array giving the red components of the entries in the + * color map. + * @param g + * the array giving the green components of the entries in the + * color map. + * @param b + * the array giving the blue components of the entries in the + * color map. + * @param trans + * the transparency supported, @see java.awt.Transparency. + * @throws IllegalArgumentException + * if the size of the color map is less than one. + * @throws ArrayIndexOutOfBoundsException + * if the size of one of the component arrays is less than the + * size of the color map. + */ + public IndexColorModel(int bits, int size, byte r[], byte g[], byte b[], int trans) { + + super(bits, IndexColorModel.createBits((trans >= 0)), ColorSpace + .getInstance(ColorSpace.CS_sRGB), (trans >= 0), false, Transparency.OPAQUE, + validateTransferType(ColorModel.getTransferType(bits))); + + createColorMap(size, r, g, b, null, trans); + checkPalette(); + } + + /** + * Instantiates a new index color model by building the color map from + * arrays of red, green, and blue values. + * + * @param bits + * the array of component masks. + * @param size + * the size of the color map. + * @param r + * the array giving the red components of the entries in the + * color map. + * @param g + * the array giving the green components of the entries in the + * color map. + * @param b + * the array giving the blue components of the entries in the + * color map. + * @throws IllegalArgumentException + * if the size of the color map is less than one. + * @throws ArrayIndexOutOfBoundsException + * if the size of one of the component arrays is less than the + * size of the color map. + */ + public IndexColorModel(int bits, int size, byte r[], byte g[], byte b[]) { + super(bits, IndexColorModel.createBits(false), ColorSpace.getInstance(ColorSpace.CS_sRGB), + false, false, Transparency.OPAQUE, validateTransferType(ColorModel + .getTransferType(bits))); + + createColorMap(size, r, g, b, null, -1); + checkPalette(); + } + + /** + * Instantiates a new index color model. + * + * @param bits + * the array of component masks. + * @param size + * the size of the color map. + * @param cmap + * the array that gives the color mapping. + * @param start + * the start index of the color mapping data within the cmap + * array. + * @param hasalpha + * whether this color model uses alpha. + * @param trans + * the transparency supported, @see java.awt.Transparency. + * @throws IllegalArgumentException + * if the size of the color map is less than one. + */ + public IndexColorModel(int bits, int size, byte cmap[], int start, boolean hasalpha, int trans) { + + super(bits, IndexColorModel.createBits(hasalpha || (trans >= 0)), ColorSpace + .getInstance(ColorSpace.CS_sRGB), (hasalpha || (trans >= 0)), false, + Transparency.OPAQUE, validateTransferType(ColorModel.getTransferType(bits))); + + if (size < 1) { + // awt.264=Size of the color map is less than 1 + throw new IllegalArgumentException(Messages.getString("awt.264")); //$NON-NLS-1$ + } + + mapSize = size; + colorMap = new int[mapSize]; + transparentIndex = -1; + + transparency = Transparency.OPAQUE; + int alpha = 0xff000000; + + for (int i = 0; i < mapSize; i++) { + colorMap[i] = (cmap[start++] & 0xff) << 16 | (cmap[start++] & 0xff) << 8 + | (cmap[start++] & 0xff); + if (trans == i) { + if (transparency == Transparency.OPAQUE) { + transparency = Transparency.BITMASK; + } + if (hasalpha) { + start++; + } + continue; + } + if (hasalpha) { + alpha = cmap[start++] & 0xff; + if (alpha == 0) { + if (transparency == Transparency.OPAQUE) { + transparency = Transparency.BITMASK; + if (trans < 0) { + trans = i; + } + } + } else { + if (alpha != 0xff && transparency != Transparency.TRANSLUCENT) { + transparency = Transparency.TRANSLUCENT; + } + } + alpha <<= 24; + } + colorMap[i] |= alpha; + } + + if (trans >= 0 && trans < mapSize) { + transparentIndex = trans; + } + checkPalette(); + + } + + /** + * Instantiates a new index color model. + * + * @param bits + * the array of component masks. + * @param size + * the size of the color map. + * @param cmap + * the array that gives the color mapping. + * @param start + * the start index of the color mapping data within the cmap + * array. + * @param hasalpha + * whether this color model uses alpha. + * @throws IllegalArgumentException + * if the size of the color map is less than one. + */ + public IndexColorModel(int bits, int size, byte cmap[], int start, boolean hasalpha) { + + this(bits, size, cmap, start, hasalpha, -1); + } + + @Override + public Object getDataElements(int[] components, int offset, Object pixel) { + int rgb = (components[offset] << 16) | (components[offset + 1]) << 8 + | components[offset + 2]; + if (hasAlpha) { + rgb |= components[offset + 3] << 24; + } else { + rgb |= 0xff000000; + } + return getDataElements(rgb, pixel); + } + + @Override + public synchronized Object getDataElements(int rgb, Object pixel) { + int red = (rgb >> 16) & 0xff; + int green = (rgb >> 8) & 0xff; + int blue = rgb & 0xff; + int alpha = rgb >>> 24; + int pixIdx = 0; + + for (int i = 0; i < totalInserted; i++) { + int idx = i * 2; + if (rgb == cachetable[idx]) { + return createDataObject(cachetable[idx + 1], pixel); + } + } + + if (!hasAlpha && grayPalette) { + int grey = (red * 77 + green * 150 + blue * 29 + 128) >>> 8; + int minError = 255; + int error = 0; + + for (int i = 0; i < mapSize; i++) { + error = Math.abs((colorMap[i] & 0xff) - grey); + if (error < minError) { + pixIdx = i; + if (error == 0) { + break; + } + minError = error; + } + } + } else if (alpha == 0 && transparentIndex > -1) { + pixIdx = transparentIndex; + } else { + int minAlphaError = 255; + int minError = 195075; // 255^2 + 255^2 + 255^2 + int alphaError; + int error = 0; + + for (int i = 0; i < mapSize; i++) { + int pix = colorMap[i]; + if (rgb == pix) { + pixIdx = i; + break; + } + alphaError = Math.abs(alpha - (pix >>> 24)); + if (alphaError <= minAlphaError) { + minAlphaError = alphaError; + + int buf = ((pix >> 16) & 0xff) - red; + error = buf * buf; + + if (error < minError) { + buf = ((pix >> 8) & 0xff) - green; + error += buf * buf; + + if (error < minError) { + buf = (pix & 0xff) - blue; + error += buf * buf; + + if (error < minError) { + pixIdx = i; + minError = error; + } + } + } + } + } + } + + cachetable[nextInsertIdx] = rgb; + cachetable[nextInsertIdx + 1] = pixIdx; + + nextInsertIdx = (nextInsertIdx + 2) % (CACHESIZE * 2); + if (totalInserted < CACHESIZE) { + totalInserted++; + } + + return createDataObject(pixIdx, pixel); + } + + /** + * Converts an image from indexed to RGB format. + * + * @param raster + * the raster containing the source image. + * @param forceARGB + * whether to use the default RGB color model. + * @return the buffered image. + * @throws IllegalArgumentException + * if the raster is not compatible with this color model. + */ + public BufferedImage convertToIntDiscrete(Raster raster, boolean forceARGB) { + + if (!isCompatibleRaster(raster)) { + // awt.265=The raster argument is not compatible with this + // IndexColorModel + throw new IllegalArgumentException(Messages.getString("awt.265")); //$NON-NLS-1$ + } + + ColorModel model; + if (forceARGB || transparency == Transparency.TRANSLUCENT) { + model = ColorModel.getRGBdefault(); + } else if (transparency == Transparency.BITMASK) { + model = new DirectColorModel(25, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x01000000); + } else { + model = new DirectColorModel(24, 0x00ff0000, 0x0000ff00, 0x000000ff); + } + + int w = raster.getWidth(); + int h = raster.getHeight(); + + WritableRaster distRaster = model.createCompatibleWritableRaster(w, h); + + int minX = raster.getMinX(); + int minY = raster.getMinY(); + + Object obj = null; + int pixels[] = null; + + for (int i = 0; i < h; i++, minY++) { + obj = raster.getDataElements(minX, minY, w, 1, obj); + if (obj instanceof byte[]) { + byte ba[] = (byte[])obj; + if (pixels == null) { + pixels = new int[ba.length]; + } + for (int j = 0; j < ba.length; j++) { + pixels[j] = colorMap[ba[j] & 0xff]; + } + } else if (obj instanceof short[]) { + short sa[] = (short[])obj; + if (pixels == null) { + pixels = new int[sa.length]; + } + for (int j = 0; j < sa.length; j++) { + pixels[j] = colorMap[sa[j] & 0xffff]; + } + } + if (obj instanceof int[]) { + int ia[] = (int[])obj; + if (pixels == null) { + pixels = new int[ia.length]; + } + for (int j = 0; j < ia.length; j++) { + pixels[j] = colorMap[ia[j]]; + } + } + + distRaster.setDataElements(0, i, w, 1, pixels); + } + + return new BufferedImage(model, distRaster, false, null); + } + + /** + * Gets the valid pixels. + * + * @return the valid pixels. + */ + public BigInteger getValidPixels() { + return validBits; + } + + @Override + public String toString() { + // The output format based on 1.5 release behaviour. + // It could be reveled such way: + // BufferedImage bi = new BufferedImage(1, 1, + // BufferedImage.TYPE_BYTE_INDEXED); + // ColorModel cm = bi.getColorModel(); + // System.out.println(cm.toString()); + String str = "IndexColorModel: #pixel_bits = " + pixel_bits + //$NON-NLS-1$ + " numComponents = " + numComponents + " color space = " + cs + //$NON-NLS-1$ //$NON-NLS-2$ + " transparency = "; //$NON-NLS-1$ + + if (transparency == Transparency.OPAQUE) { + str = str + "Transparency.OPAQUE"; //$NON-NLS-1$ + } else if (transparency == Transparency.BITMASK) { + str = str + "Transparency.BITMASK"; //$NON-NLS-1$ + } else { + str = str + "Transparency.TRANSLUCENT"; //$NON-NLS-1$ + } + + str = str + " transIndex = " + transparentIndex + " has alpha = " + //$NON-NLS-1$ //$NON-NLS-2$ + hasAlpha + " isAlphaPre = " + isAlphaPremultiplied; //$NON-NLS-1$ + + return str; + } + + @Override + public int[] getComponents(Object pixel, int components[], int offset) { + int pixIdx = -1; + if (pixel instanceof byte[]) { + byte ba[] = (byte[])pixel; + pixIdx = ba[0] & 0xff; + } else if (pixel instanceof short[]) { + short sa[] = (short[])pixel; + pixIdx = sa[0] & 0xffff; + } else if (pixel instanceof int[]) { + int ia[] = (int[])pixel; + pixIdx = ia[0]; + } else { + // awt.219=This transferType is not supported by this color model + throw new UnsupportedOperationException(Messages.getString("awt.219")); //$NON-NLS-1$ + } + + return getComponents(pixIdx, components, offset); + } + + @Override + public WritableRaster createCompatibleWritableRaster(int w, int h) { + WritableRaster raster; + if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4) { + raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, w, h, 1, pixel_bits, null); + } else if (pixel_bits <= 8) { + raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, w, h, 1, null); + } else if (pixel_bits <= 16) { + raster = Raster.createInterleavedRaster(DataBuffer.TYPE_USHORT, w, h, 1, null); + } else { + // awt.266=The number of bits in a pixel is greater than 16 + throw new UnsupportedOperationException(Messages.getString("awt.266")); //$NON-NLS-1$ + } + + return raster; + } + + @Override + public boolean isCompatibleSampleModel(SampleModel sm) { + if (sm == null) { + return false; + } + + if (!(sm instanceof MultiPixelPackedSampleModel) && !(sm instanceof ComponentSampleModel)) { + return false; + } + + if (sm.getTransferType() != transferType) { + return false; + } + if (sm.getNumBands() != 1) { + return false; + } + + return true; + } + + @Override + public SampleModel createCompatibleSampleModel(int w, int h) { + if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4) { + return new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE, w, h, pixel_bits); + } + int bandOffsets[] = new int[1]; + bandOffsets[0] = 0; + return new ComponentSampleModel(transferType, w, h, 1, w, bandOffsets); + + } + + @Override + public boolean isCompatibleRaster(Raster raster) { + int sampleSize = raster.getSampleModel().getSampleSize(0); + return (raster.getTransferType() == transferType && raster.getNumBands() == 1 && (1 << sampleSize) >= mapSize); + } + + @Override + public int getDataElement(int components[], int offset) { + int rgb = (components[offset] << 16) | (components[offset + 1]) << 8 + | components[offset + 2]; + + if (hasAlpha) { + rgb |= components[offset + 3] << 24; + } else { + rgb |= 0xff000000; + } + + int pixel; + + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte ba[] = (byte[])getDataElements(rgb, null); + pixel = ba[0] & 0xff; + break; + case DataBuffer.TYPE_USHORT: + short sa[] = (short[])getDataElements(rgb, null); + pixel = sa[0] & 0xffff; + break; + default: + // awt.267=The transferType is invalid + throw new UnsupportedOperationException(Messages.getString("awt.267")); //$NON-NLS-1$ + } + + return pixel; + } + + /** + * Gets the color map. + * + * @param rgb + * the destination array where the color map is written. + */ + public final void getRGBs(int rgb[]) { + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(colorMap, 0, rgb, 0, mapSize); + } + + /** + * Gets the red component of the color map. + * + * @param r + * the destination array. + */ + public final void getReds(byte r[]) { + for (int i = 0; i < mapSize; i++) { + r[i] = (byte)(colorMap[i] >> 16); + } + } + + /** + * Gets the green component of the color map. + * + * @param g + * the destination array. + */ + public final void getGreens(byte g[]) { + for (int i = 0; i < mapSize; i++) { + g[i] = (byte)(colorMap[i] >> 8); + } + } + + /** + * Gets the blue component of the color map. + * + * @param b + * the destination array. + */ + public final void getBlues(byte b[]) { + for (int i = 0; i < mapSize; i++) { + b[i] = (byte)colorMap[i]; + } + } + + /** + * Gets the alpha component of the color map. + * + * @param a + * the destination array. + */ + public final void getAlphas(byte a[]) { + for (int i = 0; i < mapSize; i++) { + a[i] = (byte)(colorMap[i] >> 24); + } + } + + @Override + public int[] getComponents(int pixel, int components[], int offset) { + if (components == null) { + components = new int[offset + numComponents]; + } + + components[offset + 0] = getRed(pixel); + components[offset + 1] = getGreen(pixel); + components[offset + 2] = getBlue(pixel); + if (hasAlpha && (components.length - offset) > 3) { + components[offset + 3] = getAlpha(pixel); + } + + return components; + } + + /** + * Checks if the specified pixel is valid for this color model. + * + * @param pixel + * the pixel. + * @return true, if the pixel is valid. + */ + public boolean isValid(int pixel) { + if (validBits == null) { + return (pixel >= 0 && pixel < mapSize); + } + return (pixel < mapSize && validBits.testBit(pixel)); + } + + @Override + public final int getRed(int pixel) { + return (colorMap[pixel] >> 16) & 0xff; + } + + @Override + public final int getRGB(int pixel) { + return colorMap[pixel]; + } + + @Override + public final int getGreen(int pixel) { + return (colorMap[pixel] >> 8) & 0xff; + } + + @Override + public final int getBlue(int pixel) { + return colorMap[pixel] & 0xff; + } + + @Override + public final int getAlpha(int pixel) { + return (colorMap[pixel] >> 24) & 0xff; + } + + @Override + public int[] getComponentSize() { + return bits.clone(); + } + + /** + * Checks if this color model validates pixels. + * + * @return true, if all pixels are valid, otherwise false. + */ + public boolean isValid() { + return (validBits == null); + } + + @Override + public void finalize() { + // TODO: implement + return; + } + + /** + * Gets the index that represents the transparent pixel. + * + * @return the index that represents the transparent pixel. + */ + public final int getTransparentPixel() { + return transparentIndex; + } + + @Override + public int getTransparency() { + return transparency; + } + + /** + * Gets the size of the color map. + * + * @return the map size. + */ + public final int getMapSize() { + return mapSize; + } + + /** + * Creates the color map. + * + * @param size + * the size. + * @param r + * the r. + * @param g + * the g. + * @param b + * the b. + * @param a + * the a. + * @param trans + * the trans. + */ + private void createColorMap(int size, byte r[], byte g[], byte b[], byte a[], int trans) { + if (size < 1) { + // awt.264=Size of the color map is less than 1 + throw new IllegalArgumentException(Messages.getString("awt.264")); //$NON-NLS-1$ + } + + mapSize = size; + colorMap = new int[mapSize]; + if (trans >= 0 && trans < mapSize) { + transparency = Transparency.BITMASK; + transparentIndex = trans; + } else { + transparency = Transparency.OPAQUE; + transparentIndex = -1; + } + int alpha = 0; + + for (int i = 0; i < mapSize; i++) { + colorMap[i] = ((r[i] & 0xff) << 16) | ((g[i] & 0xff) << 8) | (b[i] & 0xff); + + if (trans == i) { + continue; + } + + if (a == null) { + colorMap[i] |= 0xff000000; + } else { + alpha = a[i] & 0xff; + if (alpha == 0xff) { + colorMap[i] |= 0xff000000; + } else if (alpha == 0) { + if (transparency == Transparency.OPAQUE) { + transparency = Transparency.BITMASK; + } + if (transparentIndex < 0) { + transparentIndex = i; + } + } else { + colorMap[i] |= (a[i] & 0xff) << 24; + if (transparency != Transparency.TRANSLUCENT) { + transparency = Transparency.TRANSLUCENT; + } + } + } + + } + + } + + /** + * This method checking, if Color Map has Gray palette. + */ + private void checkPalette() { + grayPalette = false; + if (transparency > Transparency.OPAQUE) { + return; + } + int rgb = 0; + + for (int i = 0; i < mapSize; i++) { + rgb = colorMap[i]; + if (((rgb >> 16) & 0xff) != ((rgb >> 8) & 0xff) || ((rgb >> 8) & 0xff) != (rgb & 0xff)) { + return; + } + } + grayPalette = true; + } + + /** + * Construction an array pixel representation. + * + * @param colorMapIdx + * the index into Color Map. + * @param pixel + * the pixel + * @return the pixel representation array. + */ + private Object createDataObject(int colorMapIdx, Object pixel) { + if (pixel == null) { + switch (transferType) { + case DataBuffer.TYPE_BYTE: + byte[] ba = new byte[1]; + ba[0] = (byte)colorMapIdx; + pixel = ba; + break; + case DataBuffer.TYPE_USHORT: + short[] sa = new short[1]; + sa[0] = (short)colorMapIdx; + pixel = sa; + break; + default: + // awt.267=The transferType is invalid + throw new UnsupportedOperationException(Messages.getString("awt.267")); //$NON-NLS-1$ + } + } else if (pixel instanceof byte[] && transferType == DataBuffer.TYPE_BYTE) { + byte ba[] = (byte[])pixel; + ba[0] = (byte)colorMapIdx; + pixel = ba; + } else if (pixel instanceof short[] && transferType == DataBuffer.TYPE_USHORT) { + short[] sa = (short[])pixel; + sa[0] = (short)colorMapIdx; + pixel = sa; + } else if (pixel instanceof int[]) { + int ia[] = (int[])pixel; + ia[0] = colorMapIdx; + pixel = ia; + } else { + // awt.268=The pixel is not a primitive array of type transferType + throw new ClassCastException(Messages.getString("awt.268")); //$NON-NLS-1$ + } + return pixel; + } + + /** + * Creates the bits. + * + * @param hasAlpha + * the has alpha. + * @return the int[]. + */ + private static int[] createBits(boolean hasAlpha) { + + int numChannels; + if (hasAlpha) { + numChannels = 4; + } else { + numChannels = 3; + } + + int bits[] = new int[numChannels]; + for (int i = 0; i < numChannels; i++) { + bits[i] = 8; + } + + return bits; + + } + + /** + * Validate transfer type. + * + * @param transferType + * the transfer type. + * @return the int. + */ + private static int validateTransferType(int transferType) { + if (transferType != DataBuffer.TYPE_BYTE && transferType != DataBuffer.TYPE_USHORT) { + // awt.269=The transferType is not one of DataBuffer.TYPE_BYTE or + // DataBuffer.TYPE_USHORT + throw new IllegalArgumentException(Messages.getString("awt.269")); //$NON-NLS-1$ + } + return transferType; + } + + /** + * Checks if is gray palette. + * + * @return true, if is gray palette. + */ + boolean isGrayPallete() { + return grayPalette; + } + +} diff --git a/app/src/main/java/java/awt/image/Kernel.java b/app/src/main/java/java/awt/image/Kernel.java new file mode 100644 index 000000000..daf087faa --- /dev/null +++ b/app/src/main/java/java/awt/image/Kernel.java @@ -0,0 +1,153 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + * + * @date: Sep 28, 2005 + */ + +package java.awt.image; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Kernel class provides a matrix. This matrix is stored as a float array + * which describes how a specified pixel affects the value calculated for the + * pixel's position in the output image of a filtering operation. The X, Y + * origins indicate the kernel matrix element which corresponds to the pixel + * position for which an output value is being calculated. + * + * @since Android 1.0 + */ +public class Kernel implements Cloneable { + + /** + * The x origin. + */ + private final int xOrigin; + + /** + * The y origin. + */ + private final int yOrigin; + + /** + * The width. + */ + private int width; + + /** + * The height. + */ + private int height; + + /** + * The data. + */ + float data[]; + + /** + * Instantiates a new Kernel with the specified float array. The + * width*height elements of the data array are copied. + * + * @param width + * the width of the Kernel. + * @param height + * the height of the Kernel. + * @param data + * the data of Kernel. + */ + public Kernel(int width, int height, float[] data) { + int dataLength = width * height; + if (data.length < dataLength) { + // awt.22B=Length of data should not be less than width*height + throw new IllegalArgumentException(Messages.getString("awt.22B")); //$NON-NLS-1$ + } + + this.width = width; + this.height = height; + + this.data = new float[dataLength]; + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(data, 0, this.data, 0, dataLength); + + xOrigin = (width - 1) / 2; + yOrigin = (height - 1) / 2; + } + + /** + * Gets the width of this Kernel. + * + * @return the width of this Kernel. + */ + public final int getWidth() { + return width; + } + + /** + * Gets the height of this Kernel. + * + * @return the height of this Kernel. + */ + public final int getHeight() { + return height; + } + + /** + * Gets the float data array of this Kernel. + * + * @param data + * the float array where the resulted data will be stored. + * @return the float data array of this Kernel. + */ + public final float[] getKernelData(float[] data) { + if (data == null) { + data = new float[this.data.length]; + } + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(this.data, 0, data, 0, this.data.length); + + return data; + } + + /** + * Gets the X origin of this Kernel. + * + * @return the X origin of this Kernel. + */ + public final int getXOrigin() { + return xOrigin; + } + + /** + * Gets the Y origin of this Kernel. + * + * @return the Y origin of this Kernel. + */ + public final int getYOrigin() { + return yOrigin; + } + + /** + * Returns a copy of this Kernel object. + * + * @return the copy of this Kernel object. + */ + @Override + public Object clone() { + return new Kernel(width, height, data); + } +} diff --git a/app/src/main/java/java/awt/image/LookupOp.java b/app/src/main/java/java/awt/image/LookupOp.java new file mode 100644 index 000000000..af795f716 --- /dev/null +++ b/app/src/main/java/java/awt/image/LookupOp.java @@ -0,0 +1,661 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + * + * @date: Oct 14, 2005 + */ + +package java.awt.image; + +import java.awt.*; +import java.awt.geom.Rectangle2D; +import java.awt.geom.Point2D; +import java.util.Arrays; + +import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The LookupOp class performs a lookup operation which transforms a source + * image by filtering each band using a table of data. The table may contain a + * single array or it may contain a different data array for each band of the + * image. + * + * @since Android 1.0 + */ +public class LookupOp implements BufferedImageOp, RasterOp { + + /** + * The lut. + */ + private final LookupTable lut; + + /** + * The hints. + */ + private RenderingHints hints; + + // TODO remove when this field is used + /** + * The can use ipp. + */ + @SuppressWarnings("unused") + private final boolean canUseIpp; + + // We don't create levels/values when it is possible to reuse old + /** + * The cached levels. + */ + private int cachedLevels[]; + + /** + * The cached values. + */ + private int cachedValues[]; + + // Number of channels for which cache is valid. + // If negative number of channels is same as positive but skipAlpha was + // specified + /** + * The valid for channels. + */ + private int validForChannels; + + /** + * The level initializer. + */ + static int levelInitializer[] = new int[0x10000]; + + static { + // TODO + // System.loadLibrary("imageops"); + + for (int i = 1; i <= 0x10000; i++) { + levelInitializer[i - 1] = i; + } + } + + /** + * Instantiates a new LookupOp object from the specified LookupTable object + * and a RenderingHints object. + * + * @param lookup + * the specified LookupTable object. + * @param hints + * the RenderingHints object or null. + */ + public LookupOp(LookupTable lookup, RenderingHints hints) { + if (lookup == null) { + throw new NullPointerException(Messages.getString("awt.01", "lookup")); //$NON-NLS-1$ //$NON-NLS-2$ + } + lut = lookup; + this.hints = hints; + canUseIpp = lut instanceof ByteLookupTable || lut instanceof ShortLookupTable; + } + + /** + * Gets the LookupTable of the specified Object. + * + * @return the LookupTable of the specified Object. + */ + public final LookupTable getTable() { + return lut; + } + + public final RenderingHints getRenderingHints() { + return hints; + } + + public final Point2D getPoint2D(Point2D srcPt, Point2D dstPt) { + if (dstPt == null) { + dstPt = new Point2D.Float(); + } + + dstPt.setLocation(srcPt); + return dstPt; + } + + public final Rectangle2D getBounds2D(Raster src) { + return src.getBounds(); + } + + public final Rectangle2D getBounds2D(BufferedImage src) { + return getBounds2D(src.getRaster()); + } + + public WritableRaster createCompatibleDestRaster(Raster src) { + return src.createCompatibleWritableRaster(); + } + + public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel dstCM) { + if (dstCM == null) { + dstCM = src.getColorModel(); + + // Sync transfer type with LUT for component color model + if (dstCM instanceof ComponentColorModel) { + int transferType = dstCM.getTransferType(); + if (lut instanceof ByteLookupTable) { + transferType = DataBuffer.TYPE_BYTE; + } else if (lut instanceof ShortLookupTable) { + transferType = DataBuffer.TYPE_SHORT; + } + + dstCM = new ComponentColorModel(dstCM.cs, dstCM.hasAlpha(), + dstCM.isAlphaPremultiplied, dstCM.transparency, transferType); + } + } + + WritableRaster r = dstCM.isCompatibleSampleModel(src.getSampleModel()) ? src.getRaster() + .createCompatibleWritableRaster(src.getWidth(), src.getHeight()) : dstCM + .createCompatibleWritableRaster(src.getWidth(), src.getHeight()); + + return new BufferedImage(dstCM, r, dstCM.isAlphaPremultiplied(), null); + } + + public final WritableRaster filter(Raster src, WritableRaster dst) { + if (dst == null) { + dst = createCompatibleDestRaster(src); + } else { + if (src.getNumBands() != dst.getNumBands()) { + throw new IllegalArgumentException(Messages.getString("awt.237")); //$NON-NLS-1$ } + } + if (src.getWidth() != dst.getWidth()) { + throw new IllegalArgumentException(Messages.getString("awt.28F")); //$NON-NLS-1$ } + } + if (src.getHeight() != dst.getHeight()) { + throw new IllegalArgumentException(Messages.getString("awt.290")); //$NON-NLS-1$ } + } + } + + if (lut.getNumComponents() != 1 && lut.getNumComponents() != src.getNumBands()) { + // awt.238=The number of arrays in the LookupTable does not meet the + // restrictions + throw new IllegalArgumentException(Messages.getString("awt.238")); //$NON-NLS-1$ + } + + // TODO + // if (!canUseIpp || ippFilter(src, dst, BufferedImage.TYPE_CUSTOM, + // false) != 0) + if (slowFilter(src, dst, false) != 0) { + // awt.21F=Unable to transform source + throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$ + } + + return dst; + } + + public final BufferedImage filter(BufferedImage src, BufferedImage dst) { + ColorModel srcCM = src.getColorModel(); + + if (srcCM instanceof IndexColorModel) { + // awt.220=Source should not have IndexColorModel + throw new IllegalArgumentException(Messages.getString("awt.220")); //$NON-NLS-1$ + } + + // Check if the number of scaling factors matches the number of bands + int nComponents = srcCM.getNumComponents(); + int nLUTComponents = lut.getNumComponents(); + boolean skipAlpha; + if (srcCM.hasAlpha()) { + if (nLUTComponents == 1 || nLUTComponents == nComponents - 1) { + skipAlpha = true; + } else if (nLUTComponents == nComponents) { + skipAlpha = false; + } else { + // awt.229=Number of components in the LUT does not match the + // number of bands + throw new IllegalArgumentException(Messages.getString("awt.229")); //$NON-NLS-1$ + } + } else if (nLUTComponents == 1 || nLUTComponents == nComponents) { + skipAlpha = false; + } else { + // awt.229=Number of components in the LUT does not match the number + // of bands + throw new IllegalArgumentException(Messages.getString("awt.229")); //$NON-NLS-1$ + } + + BufferedImage finalDst = null; + if (dst == null) { + finalDst = dst; + dst = createCompatibleDestImage(src, null); + } else { + if (src.getWidth() != dst.getWidth()) { + throw new IllegalArgumentException(Messages.getString("awt.291")); //$NON-NLS-1$ + } + + if (src.getHeight() != dst.getHeight()) { + throw new IllegalArgumentException(Messages.getString("awt.292")); //$NON-NLS-1$ + } + + if (!srcCM.equals(dst.getColorModel())) { + // Treat BufferedImage.TYPE_INT_RGB and + // BufferedImage.TYPE_INT_ARGB as same + if (!((src.getType() == BufferedImage.TYPE_INT_RGB || src.getType() == BufferedImage.TYPE_INT_ARGB) && (dst + .getType() == BufferedImage.TYPE_INT_RGB || dst.getType() == BufferedImage.TYPE_INT_ARGB))) { + finalDst = dst; + dst = createCompatibleDestImage(src, null); + } + } + } + + // TODO + // if (!canUseIpp || ippFilter(src.getRaster(), dst.getRaster(), + // src.getType(), skipAlpha) != 0) + if (slowFilter(src.getRaster(), dst.getRaster(), skipAlpha) != 0) { + // awt.21F=Unable to transform source + throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$ + } + + if (finalDst != null) { + Graphics2D g = finalDst.createGraphics(); + g.setComposite(AlphaComposite.Src); + g.drawImage(dst, 0, 0, null); + } else { + finalDst = dst; + } + + return dst; + } + + /** + * Slow filter. + * + * @param src + * the src. + * @param dst + * the dst. + * @param skipAlpha + * the skip alpha. + * @return the int. + */ + private final int slowFilter(Raster src, WritableRaster dst, boolean skipAlpha) { + int minSrcX = src.getMinX(); + int minDstX = dst.getMinX(); + int minSrcY = src.getMinY(); + int minDstY = dst.getMinY(); + + int skippingChannels = skipAlpha ? 1 : 0; + int numBands2Process = src.getNumBands() - skippingChannels; + + int numBands = src.getNumBands(); + int srcHeight = src.getHeight(); + int srcWidth = src.getWidth(); + + int[] pixels = null; + int offset = lut.getOffset(); + + if (lut instanceof ByteLookupTable) { + byte[][] byteData = ((ByteLookupTable)lut).getTable(); + pixels = src.getPixels(minSrcX, minSrcY, srcWidth, srcHeight, pixels); + + if (lut.getNumComponents() != 1) { + for (int i = 0; i < pixels.length; i += numBands) { + for (int b = 0; b < numBands2Process; b++) { + pixels[i + b] = byteData[b][pixels[i + b] - offset] & 0xFF; + } + } + } else { + for (int i = 0; i < pixels.length; i += numBands) { + for (int b = 0; b < numBands2Process; b++) { + pixels[i + b] = byteData[0][pixels[i + b] - offset] & 0xFF; + } + } + } + + dst.setPixels(minDstX, minDstY, srcWidth, srcHeight, pixels); + } else if (lut instanceof ShortLookupTable) { + short[][] shortData = ((ShortLookupTable)lut).getTable(); + pixels = src.getPixels(minSrcX, minSrcY, srcWidth, srcHeight, pixels); + + if (lut.getNumComponents() != 1) { + for (int i = 0; i < pixels.length; i += numBands) { + for (int b = 0; b < numBands2Process; b++) { + pixels[i + b] = shortData[b][pixels[i + b] - offset] & 0xFFFF; + } + } + } else { + for (int i = 0; i < pixels.length; i += numBands) { + for (int b = 0; b < numBands2Process; b++) { + pixels[i + b] = shortData[0][pixels[i + b] - offset] & 0xFFFF; + } + } + } + + dst.setPixels(minDstX, minDstY, srcWidth, srcHeight, pixels); + } else { + int pixel[] = new int[src.getNumBands()]; + int maxY = minSrcY + srcHeight; + int maxX = minSrcX + srcWidth; + for (int srcY = minSrcY, dstY = minDstY; srcY < maxY; srcY++, dstY++) { + for (int srcX = minSrcX, dstX = minDstX; srcX < maxX; srcX++, dstX++) { + src.getPixel(srcX, srcY, pixel); + lut.lookupPixel(pixel, pixel); + dst.setPixel(dstX, dstY, pixel); + } + } + } + + return 0; + } + + /** + * Creates the byte levels. + * + * @param channels + * the channels. + * @param skipAlpha + * the skip alpha. + * @param levels + * the levels. + * @param values + * the values. + * @param channelsOrder + * the channels order. + */ + private final void createByteLevels(int channels, boolean skipAlpha, int levels[], + int values[], int channelsOrder[]) { + byte data[][] = ((ByteLookupTable)lut).getTable(); + int nLevels = data[0].length; + int offset = lut.getOffset(); + + // Use one data array for all channels or use several data arrays + int dataIncrement = data.length > 1 ? 1 : 0; + + for (int ch = 0, dataIdx = 0; ch < channels; dataIdx += dataIncrement, ch++) { + int channelOffset = channelsOrder == null ? ch : channelsOrder[ch]; + int channelBase = nLevels * channelOffset; + + // Skip last channel if needed, zero values are OK - + // no changes to the channel information will be done in IPP + if ((channelOffset == channels - 1 && skipAlpha) || (dataIdx >= data.length)) { + continue; + } + + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(levelInitializer, offset, levels, channelBase, nLevels); + for (int from = 0, to = channelBase; from < nLevels; from++, to++) { + values[to] = data[dataIdx][from] & 0xFF; + } + } + } + + /** + * Creates the short levels. + * + * @param channels + * the channels. + * @param skipAlpha + * the skip alpha. + * @param levels + * the levels. + * @param values + * the values. + * @param channelsOrder + * the channels order. + */ + private final void createShortLevels(int channels, boolean skipAlpha, int levels[], + int values[], int channelsOrder[]) { + short data[][] = ((ShortLookupTable)lut).getTable(); + int nLevels = data[0].length; + int offset = lut.getOffset(); + + // Use one data array for all channels or use several data arrays + int dataIncrement = data.length > 1 ? 1 : 0; + + for (int ch = 0, dataIdx = 0; ch < channels; dataIdx += dataIncrement, ch++) { + int channelOffset = channelsOrder == null ? ch : channelsOrder[ch]; + + // Skip last channel if needed, zero values are OK - + // no changes to the channel information will be done in IPP + if ((channelOffset == channels - 1 && skipAlpha) || (dataIdx >= data.length)) { + continue; + } + + int channelBase = nLevels * channelOffset; + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(levelInitializer, offset, levels, channelBase, nLevels); + for (int from = 0, to = channelBase; from < nLevels; from++, to++) { + values[to] = data[dataIdx][from] & 0xFFFF; + } + } + } + + // TODO remove when this method is used + /** + * Ipp filter. + * + * @param src + * the src. + * @param dst + * the dst. + * @param imageType + * the image type. + * @param skipAlpha + * the skip alpha. + * @return the int. + */ + @SuppressWarnings("unused") + private final int ippFilter(Raster src, WritableRaster dst, int imageType, boolean skipAlpha) { + int res; + + int srcStride, dstStride; + int channels; + int offsets[] = null; + int channelsOrder[] = null; + + switch (imageType) { + case BufferedImage.TYPE_INT_ARGB: + case BufferedImage.TYPE_INT_ARGB_PRE: + case BufferedImage.TYPE_INT_RGB: { + channels = 4; + srcStride = src.getWidth() * 4; + dstStride = dst.getWidth() * 4; + channelsOrder = new int[] { + 2, 1, 0, 3 + }; + break; + } + + case BufferedImage.TYPE_4BYTE_ABGR: + case BufferedImage.TYPE_4BYTE_ABGR_PRE: + case BufferedImage.TYPE_INT_BGR: { + channels = 4; + srcStride = src.getWidth() * 4; + dstStride = dst.getWidth() * 4; + break; + } + + case BufferedImage.TYPE_BYTE_GRAY: { + channels = 1; + srcStride = src.getWidth(); + dstStride = dst.getWidth(); + break; + } + + case BufferedImage.TYPE_3BYTE_BGR: { + channels = 3; + srcStride = src.getWidth() * 3; + dstStride = dst.getWidth() * 3; + channelsOrder = new int[] { + 2, 1, 0 + }; + break; + } + + case BufferedImage.TYPE_USHORT_GRAY: + case BufferedImage.TYPE_USHORT_565_RGB: + case BufferedImage.TYPE_USHORT_555_RGB: + case BufferedImage.TYPE_BYTE_BINARY: { + return slowFilter(src, dst, skipAlpha); + } + + default: { + SampleModel srcSM = src.getSampleModel(); + SampleModel dstSM = dst.getSampleModel(); + + if (srcSM instanceof PixelInterleavedSampleModel + && dstSM instanceof PixelInterleavedSampleModel) { + // Check PixelInterleavedSampleModel + if (srcSM.getDataType() != DataBuffer.TYPE_BYTE + || dstSM.getDataType() != DataBuffer.TYPE_BYTE) { + return slowFilter(src, dst, skipAlpha); + } + + // Have IPP functions for 1, 3 and 4 channels + channels = srcSM.getNumBands(); + if (!(channels == 1 || channels == 3 || channels == 4)) { + return slowFilter(src, dst, skipAlpha); + } + + srcStride = ((ComponentSampleModel)srcSM).getScanlineStride(); + dstStride = ((ComponentSampleModel)dstSM).getScanlineStride(); + + channelsOrder = ((ComponentSampleModel)srcSM).getBandOffsets(); + } else if (srcSM instanceof SinglePixelPackedSampleModel + && dstSM instanceof SinglePixelPackedSampleModel) { + // Check SinglePixelPackedSampleModel + SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel)srcSM; + SinglePixelPackedSampleModel sppsm2 = (SinglePixelPackedSampleModel)dstSM; + + channels = sppsm1.getNumBands(); + + // TYPE_INT_RGB, TYPE_INT_ARGB... + if (sppsm1.getDataType() != DataBuffer.TYPE_INT + || sppsm2.getDataType() != DataBuffer.TYPE_INT + || !(channels == 3 || channels == 4)) { + return slowFilter(src, dst, skipAlpha); + } + + // Check compatibility of sample models + if (!Arrays.equals(sppsm1.getBitOffsets(), sppsm2.getBitOffsets()) + || !Arrays.equals(sppsm1.getBitMasks(), sppsm2.getBitMasks())) { + return slowFilter(src, dst, skipAlpha); + } + + for (int i = 0; i < channels; i++) { + if (sppsm1.getSampleSize(i) != 8) { + return slowFilter(src, dst, skipAlpha); + } + } + + channelsOrder = new int[channels]; + int bitOffsets[] = sppsm1.getBitOffsets(); + for (int i = 0; i < channels; i++) { + channelsOrder[i] = bitOffsets[i] / 8; + } + + if (channels == 3) { // Don't skip channel now, could be + // optimized + channels = 4; + } + + srcStride = sppsm1.getScanlineStride() * 4; + dstStride = sppsm2.getScanlineStride() * 4; + } else { + return slowFilter(src, dst, skipAlpha); + } + + // Fill offsets if there's a child raster + if (src.getParent() != null || dst.getParent() != null) { + if (src.getSampleModelTranslateX() != 0 || src.getSampleModelTranslateY() != 0 + || dst.getSampleModelTranslateX() != 0 + || dst.getSampleModelTranslateY() != 0) { + offsets = new int[4]; + offsets[0] = -src.getSampleModelTranslateX() + src.getMinX(); + offsets[1] = -src.getSampleModelTranslateY() + src.getMinY(); + offsets[2] = -dst.getSampleModelTranslateX() + dst.getMinX(); + offsets[3] = -dst.getSampleModelTranslateY() + dst.getMinY(); + } + } + } + } + + int levels[] = null, values[] = null; + int channelMultiplier = skipAlpha ? -1 : 1; + if (channelMultiplier * channels == validForChannels) { // use existing + // levels/values + levels = cachedLevels; + values = cachedValues; + } else { // create new levels/values + if (lut instanceof ByteLookupTable) { + byte data[][] = ((ByteLookupTable)lut).getTable(); + levels = new int[channels * data[0].length]; + values = new int[channels * data[0].length]; + createByteLevels(channels, skipAlpha, levels, values, channelsOrder); + } else if (lut instanceof ShortLookupTable) { + short data[][] = ((ShortLookupTable)lut).getTable(); + levels = new int[channels * data[0].length]; + values = new int[channels * data[0].length]; + createShortLevels(channels, skipAlpha, levels, values, channelsOrder); + } + + // cache levels/values + validForChannels = channelMultiplier * channels; + cachedLevels = levels; + cachedValues = values; + } + + Object srcData, dstData; + AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance(); + try { + srcData = dbAccess.getData(src.getDataBuffer()); + dstData = dbAccess.getData(dst.getDataBuffer()); + } catch (IllegalArgumentException e) { + return -1; // Unknown data buffer type + } + + res = ippLUT(srcData, src.getWidth(), src.getHeight(), srcStride, dstData, dst.getWidth(), + dst.getHeight(), dstStride, levels, values, channels, offsets, false); + + return res; + } + + /** + * Ipp lut. + * + * @param src + * the src. + * @param srcWidth + * the src width. + * @param srcHeight + * the src height. + * @param srcStride + * the src stride. + * @param dst + * the dst. + * @param dstWidth + * the dst width. + * @param dstHeight + * the dst height. + * @param dstStride + * the dst stride. + * @param levels + * the levels. + * @param values + * the values. + * @param channels + * the channels. + * @param offsets + * the offsets. + * @param linear + * the linear. + * @return the int. + */ + final static native int ippLUT(Object src, int srcWidth, int srcHeight, int srcStride, + Object dst, int dstWidth, int dstHeight, int dstStride, int levels[], int values[], + int channels, int offsets[], boolean linear); +} diff --git a/app/src/main/java/java/awt/image/LookupTable.java b/app/src/main/java/java/awt/image/LookupTable.java new file mode 100644 index 000000000..e465a54b2 --- /dev/null +++ b/app/src/main/java/java/awt/image/LookupTable.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + * + * @date: Oct 14, 2005 + */ + +package java.awt.image; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * This abstract LookupTable class represents lookup table which is defined with + * the number of components and offset value. ByteLookupTable and + * ShortLookupTable classes are subclasses of LookupTable which contains byte + * and short data tables as an input arrays for bands or components of image. + * + * @since Android 1.0 + */ +public abstract class LookupTable { + + /** + * The offset. + */ + private int offset; + + /** + * The num components. + */ + private int numComponents; + + /** + * Instantiates a new LookupTable with the specified offset value and number + * of components. + * + * @param offset + * the offset value. + * @param numComponents + * the number of components. + */ + protected LookupTable(int offset, int numComponents) { + if (offset < 0) { + // awt.232=Offset should be not less than zero + throw new IllegalArgumentException(Messages.getString("awt.232")); //$NON-NLS-1$ + } + if (numComponents < 1) { + // awt.233=Number of components should be positive + throw new IllegalArgumentException(Messages.getString("awt.233")); //$NON-NLS-1$ + } + + this.offset = offset; + this.numComponents = numComponents; + } + + /** + * Gets the offset value of this Lookup table. + * + * @return the offset value of this Lookup table. + */ + public int getOffset() { + return offset; + } + + /** + * Gets the number of components of this Lookup table. + * + * @return the number components of this Lookup table. + */ + public int getNumComponents() { + return numComponents; + } + + /** + * Returns an integer array which contains samples of the specified pixel which + * is translated with the lookup table of this LookupTable. The resulted + * array is stored to the dst array. + * + * @param src + * the source array. + * @param dst + * the destination array where the result can be stored. + * @return the integer array of translated samples of a pixel. + */ + public abstract int[] lookupPixel(int[] src, int[] dst); +} diff --git a/app/src/main/java/java/awt/image/MemoryImageSource.java b/app/src/main/java/java/awt/image/MemoryImageSource.java new file mode 100644 index 000000000..644fd40fe --- /dev/null +++ b/app/src/main/java/java/awt/image/MemoryImageSource.java @@ -0,0 +1,603 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.util.Hashtable; +import java.util.Vector; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The MemoryImageSource class is used to produces pixels of an image from an + * array. This class can manage a memory image which contains an animation or + * custom rendering. + * + * @since Android 1.0 + */ +public class MemoryImageSource implements ImageProducer { + + /** + * The width. + */ + int width; + + /** + * The height. + */ + int height; + + /** + * The cm. + */ + ColorModel cm; + + /** + * The b data. + */ + byte bData[]; + + /** + * The i data. + */ + int iData[]; + + /** + * The offset. + */ + int offset; + + /** + * The scanline. + */ + int scanline; + + /** + * The properties. + */ + Hashtable properties; + + /** + * The consumers. + */ + Vector consumers; + + /** + * The animated. + */ + boolean animated; + + /** + * The fullbuffers. + */ + boolean fullbuffers; + + /** + * The data type. + */ + int dataType; + + /** + * The Constant DATA_TYPE_BYTE. + */ + static final int DATA_TYPE_BYTE = 0; + + /** + * The Constant DATA_TYPE_INT. + */ + static final int DATA_TYPE_INT = 1; + + /** + * Instantiates a new MemoryImageSource with the specified parameters. + * + * @param w + * the width of the rectangular area of pixels. + * @param h + * the height of the rectangular area of pixels. + * @param cm + * the specified ColorModel. + * @param pix + * the pixel array. + * @param off + * the offset in the pixel array. + * @param scan + * the distance from one pixel's row to the next in the pixel + * array. + * @param props + * the set of properties to be used for image processing. + */ + public MemoryImageSource(int w, int h, ColorModel cm, int pix[], int off, int scan, + Hashtable props) { + init(w, h, cm, pix, off, scan, props); + } + + /** + * Instantiates a new MemoryImageSource with the specified parameters. + * + * @param w + * the width of the rectangular area of pixels. + * @param h + * the height of the rectangular area of pixels. + * @param cm + * the specified ColorModel. + * @param pix + * the pixel array. + * @param off + * the offset in the pixel array. + * @param scan + * the distance from one pixel's row to the next in the pixel + * array. + * @param props + * the set of properties to be used for image processing. + */ + public MemoryImageSource(int w, int h, ColorModel cm, byte pix[], int off, int scan, + Hashtable props) { + init(w, h, cm, pix, off, scan, props); + } + + /** + * Instantiates a new MemoryImageSource with the specified parameters and + * default RGB ColorModel. + * + * @param w + * the width of the rectangular area of pixels. + * @param h + * the height of the rectangular area of pixels. + * @param pix + * the pixel array. + * @param off + * the offset in the pixel array. + * @param scan + * the distance from one pixel's row to the next in the pixel + * array. + * @param props + * the set of properties to be used for image processing. + */ + public MemoryImageSource(int w, int h, int pix[], int off, int scan, Hashtable props) { + init(w, h, ColorModel.getRGBdefault(), pix, off, scan, props); + } + + /** + * Instantiates a new MemoryImageSource with the specified parameters. + * + * @param w + * the width of the rectangular area of pixels. + * @param h + * the height of the rectangular area of pixels. + * @param cm + * the specified ColorModel. + * @param pix + * the pixel array. + * @param off + * the offset in the pixel array. + * @param scan + * the distance from one pixel's row to the next in the pixel + * array. + */ + public MemoryImageSource(int w, int h, ColorModel cm, int pix[], int off, int scan) { + init(w, h, cm, pix, off, scan, null); + } + + /** + * Instantiates a new MemoryImageSource with the specified parameters. + * + * @param w + * the width of the rectangular area of pixels. + * @param h + * the height of the rectangular area of pixels. + * @param cm + * the specified ColorModel. + * @param pix + * the pixel array. + * @param off + * the offset in the pixel array. + * @param scan + * the distance from one pixel's row to the next in the pixel + * array. + */ + public MemoryImageSource(int w, int h, ColorModel cm, byte pix[], int off, int scan) { + init(w, h, cm, pix, off, scan, null); + } + + /** + * Instantiates a new MemoryImageSource with the specified parameters and + * default RGB ColorModel. + * + * @param w + * the width of the rectangular area of pixels. + * @param h + * the height of the rectangular area of pixels. + * @param pix + * the pixels array. + * @param off + * the offset in the pixel array. + * @param scan + * the distance from one pixel's row to the next in the pixel + * array. + */ + public MemoryImageSource(int w, int h, int pix[], int off, int scan) { + init(w, h, ColorModel.getRGBdefault(), pix, off, scan, null); + } + + public synchronized boolean isConsumer(ImageConsumer ic) { + return consumers.contains(ic); + } + + public void startProduction(ImageConsumer ic) { + if (!isConsumer(ic) && ic != null) { + consumers.addElement(ic); + } + try { + setHeader(ic); + setPixels(ic, 0, 0, width, height); + if (animated) { + ic.imageComplete(ImageConsumer.SINGLEFRAMEDONE); + } else { + ic.imageComplete(ImageConsumer.STATICIMAGEDONE); + if (isConsumer(ic)) { + removeConsumer(ic); + } + } + } catch (Exception e) { + if (isConsumer(ic)) { + ic.imageComplete(ImageConsumer.IMAGEERROR); + } + if (isConsumer(ic)) { + removeConsumer(ic); + } + } + } + + public void requestTopDownLeftRightResend(ImageConsumer ic) { + } + + public synchronized void removeConsumer(ImageConsumer ic) { + consumers.removeElement(ic); + } + + public synchronized void addConsumer(ImageConsumer ic) { + if (ic == null || consumers.contains(ic)) { + return; + } + consumers.addElement(ic); + } + + /** + * Replaces the pixel data with a new pixel array for holding the pixels for + * this image. If an animation flag is set to true value by the + * setAnimated() method, the new pixels will be immediately delivered to the + * ImageConsumers. + * + * @param newpix + * the new pixel array. + * @param newmodel + * the new ColorModel. + * @param offset + * the offset in the array. + * @param scansize + * the distance from one row of pixels to the next row in the + * pixel array. + */ + public synchronized void newPixels(int newpix[], ColorModel newmodel, int offset, int scansize) { + this.dataType = DATA_TYPE_INT; + this.iData = newpix; + this.cm = newmodel; + this.offset = offset; + this.scanline = scansize; + newPixels(); + } + + /** + * Replaces the pixel data with a new pixel array for holding the pixels for + * this image. If an animation flag is set to true value by the + * setAnimated() method, the new pixels will be immediately delivered to the + * ImageConsumers. + * + * @param newpix + * the new pixel array. + * @param newmodel + * the new ColorModel. + * @param offset + * the offset in the array. + * @param scansize + * the distance from one row of pixels to the next row in the + * pixel array. + */ + public synchronized void newPixels(byte newpix[], ColorModel newmodel, int offset, int scansize) { + this.dataType = DATA_TYPE_BYTE; + this.bData = newpix; + this.cm = newmodel; + this.offset = offset; + this.scanline = scansize; + newPixels(); + } + + /** + * Sets the full buffer updates flag to true. If this is an animated image, + * the image consumers hints are updated accordingly. + * + * @param fullbuffers + * the true if the pixel buffer should be sent always. + */ + public synchronized void setFullBufferUpdates(boolean fullbuffers) { + if (this.fullbuffers == fullbuffers) { + return; + } + this.fullbuffers = fullbuffers; + if (animated) { + Object consAr[] = consumers.toArray(); + for (Object element : consAr) { + ImageConsumer con = (ImageConsumer)element; + try { + if (fullbuffers) { + con.setHints(ImageConsumer.TOPDOWNLEFTRIGHT + | ImageConsumer.COMPLETESCANLINES); + } else { + con.setHints(ImageConsumer.RANDOMPIXELORDER); + } + } catch (Exception e) { + if (isConsumer(con)) { + con.imageComplete(ImageConsumer.IMAGEERROR); + } + if (isConsumer(con)) { + removeConsumer(con); + } + } + } + } + } + + /** + * Sets the flag that tells whether this memory image has more than one + * frame (for animation): true for multiple frames, false if this class + * represents a single frame image. + * + * @param animated + * whether this image represents an animation. + */ + public synchronized void setAnimated(boolean animated) { + if (this.animated == animated) { + return; + } + Object consAr[] = consumers.toArray(); + for (Object element : consAr) { + ImageConsumer con = (ImageConsumer)element; + try { + con.imageComplete(ImageConsumer.STATICIMAGEDONE); + } catch (Exception e) { + if (isConsumer(con)) { + con.imageComplete(ImageConsumer.IMAGEERROR); + } + } + if (isConsumer(con)) { + removeConsumer(con); + } + } + this.animated = animated; + } + + /** + * Sends the specified rectangular area of the buffer to ImageConsumers and + * notifies them that an animation frame is completed only if the {@code + * framenotify} parameter is true. That works only if the animated flag has + * been set to true by the setAnimated() method. If the full buffer update + * flag has been set to true by the setFullBufferUpdates() method, then the + * entire buffer will always be sent ignoring parameters. + * + * @param x + * the X coordinate of the rectangular area. + * @param y + * the Y coordinate of the rectangular area. + * @param w + * the width of the rectangular area. + * @param h + * the height of the rectangular area. + * @param framenotify + * true if a SINGLEFRAMEDONE notification should be sent to the + * registered consumers, false otherwise. + */ + public synchronized void newPixels(int x, int y, int w, int h, boolean framenotify) { + if (animated) { + if (fullbuffers) { + x = 0; + y = 0; + w = width; + h = height; + } else { + if (x < 0) { + w += x; + x = 0; + } + if (w > width) { + w = width - x; + } + if (y < 0) { + h += y; + y = 0; + } + } + if (h > height) { + h = height - y; + } + Object consAr[] = consumers.toArray(); + for (Object element : consAr) { + ImageConsumer con = (ImageConsumer)element; + try { + if (w > 0 && h > 0) { + setPixels(con, x, y, w, h); + } + if (framenotify) { + con.imageComplete(ImageConsumer.SINGLEFRAMEDONE); + } + } catch (Exception ex) { + if (isConsumer(con)) { + con.imageComplete(ImageConsumer.IMAGEERROR); + } + if (isConsumer(con)) { + removeConsumer(con); + } + } + } + } + } + + /** + * Sends the specified rectangular area of the buffer to the ImageConsumers + * and notifies them that an animation frame is completed if the animated + * flag has been set to true by the setAnimated() method. If the full buffer + * update flag has been set to true by the setFullBufferUpdates() method, + * then the entire buffer will always be sent ignoring parameters. + * + * @param x + * the X coordinate of the rectangular area. + * @param y + * the Y coordinate of the rectangular area. + * @param w + * the width of the rectangular area. + * @param h + * the height of the rectangular area. + */ + public synchronized void newPixels(int x, int y, int w, int h) { + newPixels(x, y, w, h, true); + } + + /** + * Sends a new buffer of pixels to the ImageConsumers and notifies them that + * an animation frame is completed if the animated flag has been set to true + * by the setAnimated() method. + */ + public void newPixels() { + newPixels(0, 0, width, height, true); + } + + /** + * Inits the. + * + * @param width + * the width. + * @param height + * the height. + * @param model + * the model. + * @param pixels + * the pixels. + * @param off + * the off. + * @param scan + * the scan. + * @param prop + * the prop. + */ + private void init(int width, int height, ColorModel model, byte pixels[], int off, int scan, + Hashtable prop) { + + this.width = width; + this.height = height; + this.cm = model; + this.bData = pixels; + this.offset = off; + this.scanline = scan; + this.properties = prop; + this.dataType = DATA_TYPE_BYTE; + this.consumers = new Vector(); + + } + + /** + * Inits the. + * + * @param width + * the width. + * @param height + * the height. + * @param model + * the model. + * @param pixels + * the pixels. + * @param off + * the off. + * @param scan + * the scan. + * @param prop + * the prop. + */ + private void init(int width, int height, ColorModel model, int pixels[], int off, int scan, + Hashtable prop) { + + this.width = width; + this.height = height; + this.cm = model; + this.iData = pixels; + this.offset = off; + this.scanline = scan; + this.properties = prop; + this.dataType = DATA_TYPE_INT; + this.consumers = new Vector(); + } + + /** + * Sets the pixels. + * + * @param con + * the con. + * @param x + * the x. + * @param y + * the y. + * @param w + * the w. + * @param h + * the h. + */ + private void setPixels(ImageConsumer con, int x, int y, int w, int h) { + int pixelOff = scanline * y + offset + x; + + switch (dataType) { + case DATA_TYPE_BYTE: + con.setPixels(x, y, w, h, cm, bData, pixelOff, scanline); + break; + case DATA_TYPE_INT: + con.setPixels(x, y, w, h, cm, iData, pixelOff, scanline); + break; + default: + // awt.22A=Wrong type of pixels array + throw new IllegalArgumentException(Messages.getString("awt.22A")); //$NON-NLS-1$ + } + } + + /** + * Sets the header. + * + * @param con + * the new header. + */ + private synchronized void setHeader(ImageConsumer con) { + con.setDimensions(width, height); + con.setProperties(properties); + con.setColorModel(cm); + con + .setHints(animated ? (fullbuffers ? (ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES) + : ImageConsumer.RANDOMPIXELORDER) + : (ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES + | ImageConsumer.SINGLEPASS | ImageConsumer.SINGLEFRAME)); + } + +} diff --git a/app/src/main/java/java/awt/image/MultiPixelPackedSampleModel.java b/app/src/main/java/java/awt/image/MultiPixelPackedSampleModel.java new file mode 100644 index 000000000..3dc13d8f4 --- /dev/null +++ b/app/src/main/java/java/awt/image/MultiPixelPackedSampleModel.java @@ -0,0 +1,479 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The MultiPixelPackedSampleModel class represents image data with one band. + * This class packs multiple pixels with one sample in one data element and + * supports the following data types: DataBuffer.TYPE_BYTE, + * DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT. + * + * @since Android 1.0 + */ +public class MultiPixelPackedSampleModel extends SampleModel { + + /** + * The pixel bit stride. + */ + private int pixelBitStride; + + /** + * The scanline stride. + */ + private int scanlineStride; + + /** + * The data bit offset. + */ + private int dataBitOffset; + + /** + * The bit mask. + */ + private int bitMask; + + /** + * The data element size. + */ + private int dataElementSize; + + /** + * The pixels per data element. + */ + private int pixelsPerDataElement; + + /** + * Instantiates a new MultiPixelPackedSampleModel with the specified + * parameters. + * + * @param dataType + * the data type of the samples. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param numberOfBits + * the number of bits per pixel. + * @param scanlineStride + * the scanline stride of the of the image data. + * @param dataBitOffset + * the array of the band offsets. + */ + public MultiPixelPackedSampleModel(int dataType, int w, int h, int numberOfBits, + int scanlineStride, int dataBitOffset) { + + super(dataType, w, h, 1); + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT + && dataType != DataBuffer.TYPE_INT) { + // awt.61=Unsupported data type: {0} + throw new IllegalArgumentException(Messages.getString("awt.61", //$NON-NLS-1$ + dataType)); + } + + this.scanlineStride = scanlineStride; + if (numberOfBits == 0) { + // awt.20C=Number of Bits equals to zero + throw new RasterFormatException(Messages.getString("awt.20C")); //$NON-NLS-1$ + } + this.pixelBitStride = numberOfBits; + this.dataElementSize = DataBuffer.getDataTypeSize(dataType); + if (dataElementSize % pixelBitStride != 0) { + // awt.20D=The number of bits per pixel is not a power of 2 or + // pixels span data element boundaries + throw new RasterFormatException(Messages.getString("awt.20D")); //$NON-NLS-1$ + } + + if (dataBitOffset % numberOfBits != 0) { + // awt.20E=Data Bit offset is not a multiple of pixel bit stride + throw new RasterFormatException(Messages.getString("awt.20E")); //$NON-NLS-1$ + } + this.dataBitOffset = dataBitOffset; + + this.pixelsPerDataElement = dataElementSize / pixelBitStride; + this.bitMask = (1 << numberOfBits) - 1; + } + + /** + * Instantiates a new MultiPixelPackedSampleModel with the specified + * parameters. + * + * @param dataType + * the data type of the samples. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param numberOfBits + * the number of bits per pixel. + */ + public MultiPixelPackedSampleModel(int dataType, int w, int h, int numberOfBits) { + + this(dataType, w, h, numberOfBits, + (numberOfBits * w + DataBuffer.getDataTypeSize(dataType) - 1) + / DataBuffer.getDataTypeSize(dataType), 0); + } + + @Override + public Object getDataElements(int x, int y, Object obj, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + switch (getTransferType()) { + case DataBuffer.TYPE_BYTE: + byte bdata[]; + if (obj == null) { + bdata = new byte[1]; + } else { + bdata = (byte[])obj; + } + bdata[0] = (byte)getSample(x, y, 0, data); + obj = bdata; + break; + case DataBuffer.TYPE_USHORT: + short sdata[]; + if (obj == null) { + sdata = new short[1]; + } else { + sdata = (short[])obj; + } + sdata[0] = (short)getSample(x, y, 0, data); + obj = sdata; + break; + case DataBuffer.TYPE_INT: + int idata[]; + if (obj == null) { + idata = new int[1]; + } else { + idata = (int[])obj; + } + idata[0] = getSample(x, y, 0, data); + obj = idata; + break; + } + + return obj; + } + + @Override + public void setDataElements(int x, int y, Object obj, DataBuffer data) { + setSample(x, y, obj, data, 1, 0); + } + + /** + * Compares this MultiPixelPackedSampleModel object with the specified + * object. + * + * @param o + * the Object to be compared. + * @return true, if the object is a MultiPixelPackedSampleModel with the + * same data parameter values as this MultiPixelPackedSampleModel, + * false otherwise. + */ + @Override + public boolean equals(Object o) { + if ((o == null) || !(o instanceof MultiPixelPackedSampleModel)) { + return false; + } + + MultiPixelPackedSampleModel model = (MultiPixelPackedSampleModel)o; + return this.width == model.width && this.height == model.height + && this.numBands == model.numBands && this.dataType == model.dataType + && this.pixelBitStride == model.pixelBitStride && this.bitMask == model.bitMask + && this.pixelsPerDataElement == model.pixelsPerDataElement + && this.dataElementSize == model.dataElementSize + && this.dataBitOffset == model.dataBitOffset + && this.scanlineStride == model.scanlineStride; + } + + @Override + public SampleModel createSubsetSampleModel(int bands[]) { + if (bands != null && bands.length != 1) { + // awt.20F=Number of bands must be only 1 + throw new RasterFormatException(Messages.getString("awt.20F")); //$NON-NLS-1$ + } + return createCompatibleSampleModel(width, height); + } + + @Override + public SampleModel createCompatibleSampleModel(int w, int h) { + return new MultiPixelPackedSampleModel(dataType, w, h, pixelBitStride); + } + + @Override + public int[] getPixel(int x, int y, int iArray[], DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int pixel[]; + if (iArray == null) { + pixel = new int[numBands]; + } else { + pixel = iArray; + } + + pixel[0] = getSample(x, y, 0, data); + return pixel; + } + + @Override + public void setPixel(int x, int y, int iArray[], DataBuffer data) { + setSample(x, y, iArray, data, 2, 0); + } + + @Override + public int getSample(int x, int y, int b, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height || b != 0) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + int bitnum = dataBitOffset + x * pixelBitStride; + int elem = data.getElem(y * scanlineStride + bitnum / dataElementSize); + int shift = dataElementSize - (bitnum & (dataElementSize - 1)) - pixelBitStride; + + return (elem >> shift) & bitMask; + } + + @Override + public void setSample(int x, int y, int b, int s, DataBuffer data) { + if (b != 0) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + setSample(x, y, null, data, 3, s); + } + + @Override + public DataBuffer createDataBuffer() { + DataBuffer dataBuffer = null; + int size = scanlineStride * height; + + switch (dataType) { + case DataBuffer.TYPE_BYTE: + dataBuffer = new DataBufferByte(size + (dataBitOffset + 7) / 8); + break; + case DataBuffer.TYPE_USHORT: + dataBuffer = new DataBufferUShort(size + (dataBitOffset + 15) / 16); + break; + case DataBuffer.TYPE_INT: + dataBuffer = new DataBufferInt(size + (dataBitOffset + 31) / 32); + break; + } + return dataBuffer; + } + + /** + * Gets the offset of the specified pixel in the data array. + * + * @param x + * the X coordinate of the specified pixel. + * @param y + * the Y coordinate of the specified pixel. + * @return the offset of the specified pixel. + */ + public int getOffset(int x, int y) { + return y * scanlineStride + (x * pixelBitStride + dataBitOffset) / dataElementSize; + } + + @Override + public int getSampleSize(int band) { + return pixelBitStride; + } + + /** + * Gets the bit offset in the data element which is stored for the specified + * pixel of a scanline. + * + * @param x + * the pixel. + * @return the bit offset of the pixel in the data element. + */ + public int getBitOffset(int x) { + return (x * pixelBitStride + dataBitOffset) % dataElementSize; + } + + @Override + public int[] getSampleSize() { + int sampleSizes[] = { + pixelBitStride + }; + return sampleSizes; + } + + /** + * Returns a hash code of this MultiPixelPackedSampleModel class. + * + * @return the hash code of this MultiPixelPackedSampleModel class. + */ + @Override + public int hashCode() { + int hash = 0; + int tmp = 0; + + hash = width; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= height; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= numBands; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= dataType; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= scanlineStride; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= pixelBitStride; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= dataBitOffset; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= bitMask; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= dataElementSize; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= pixelsPerDataElement; + return hash; + } + + @Override + public int getTransferType() { + if (pixelBitStride > 16) { + return DataBuffer.TYPE_INT; + } else if (pixelBitStride > 8) { + return DataBuffer.TYPE_USHORT; + } else { + return DataBuffer.TYPE_BYTE; + } + } + + /** + * Gets the scanline stride of this MultiPixelPackedSampleModel. + * + * @return the scanline stride of this MultiPixelPackedSampleModel. + */ + public int getScanlineStride() { + return scanlineStride; + } + + /** + * Gets the pixel bit stride of this MultiPixelPackedSampleModel. + * + * @return the pixel bit stride of this MultiPixelPackedSampleModel. + */ + public int getPixelBitStride() { + return pixelBitStride; + } + + @Override + public int getNumDataElements() { + return 1; + } + + /** + * Gets the data bit offset. + * + * @return the data bit offset. + */ + public int getDataBitOffset() { + return dataBitOffset; + } + + /** + * This method is used by other methods of this class. The behavior of this + * method depends on the method which has been invoke this one. The argument + * methodId is used to choose valid behavior in a particular case. If + * methodId is equal to 1 it means that this method has been invoked by the + * setDataElements() method, 2 - means setPixel(), and setSample() in any + * other cases. + * + * @param x + * the x. + * @param y + * the y. + * @param obj + * the obj. + * @param data + * the data. + * @param methodId + * the method id. + * @param s + * the s. + */ + private void setSample(final int x, final int y, final Object obj, final DataBuffer data, + final int methodId, int s) { + if ((x < 0) || (y < 0) || (x >= this.width) || (y >= this.height)) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + final int bitnum = dataBitOffset + x * pixelBitStride; + final int idx = y * scanlineStride + bitnum / dataElementSize; + final int shift = dataElementSize - (bitnum & (dataElementSize - 1)) - pixelBitStride; + final int mask = ~(bitMask << shift); + int elem = data.getElem(idx); + + switch (methodId) { + case 1: { // Invoked from setDataElements() + switch (getTransferType()) { + case DataBuffer.TYPE_BYTE: + s = ((byte[])obj)[0] & 0xff; + break; + case DataBuffer.TYPE_USHORT: + s = ((short[])obj)[0] & 0xffff; + break; + case DataBuffer.TYPE_INT: + s = ((int[])obj)[0]; + break; + } + break; + } + case 2: { // Invoked from setPixel() + s = ((int[])obj)[0]; + break; + } + } + + elem &= mask; + elem |= (s & bitMask) << shift; + data.setElem(idx, elem); + } +} diff --git a/app/src/main/java/java/awt/image/PackedColorModel.java b/app/src/main/java/java/awt/image/PackedColorModel.java new file mode 100644 index 000000000..4d1c2e500 --- /dev/null +++ b/app/src/main/java/java/awt/image/PackedColorModel.java @@ -0,0 +1,402 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.awt.Transparency; +import java.awt.color.ColorSpace; +import java.util.Arrays; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The class PackedColorModel represents a color model where the components are + * just the red, green, and blue bands, plus an alpha band if alpha is + * supported. + * + * @since Android 1.0 + */ +public abstract class PackedColorModel extends ColorModel { + + /** + * The component masks. + */ + int componentMasks[]; + + /** + * The offsets. + */ + int offsets[]; + + /** + * The scales. + */ + float scales[]; + + /** + * Instantiates a new packed color model. + * + * @param space + * the color space. + * @param bits + * the array of component masks. + * @param colorMaskArray + * the array that gives the bitmask corresponding to each color + * band (red, green, and blue). + * @param alphaMask + * the bitmask corresponding to the alpha band. + * @param isAlphaPremultiplied + * whether the alpha is pre-multiplied in this color model. + * @param trans + * the transparency strategy, @see java.awt.Transparency. + * @param transferType + * the transfer type (primitive java type to use for the + * components). + * @throws IllegalArgumentException + * if the number of bits in the combined bitmasks for the color + * bands is less than one or greater than 32. + */ + public PackedColorModel(ColorSpace space, int bits, int colorMaskArray[], int alphaMask, + boolean isAlphaPremultiplied, int trans, int transferType) { + + super(bits, createBits(colorMaskArray, alphaMask), space, (alphaMask == 0 ? false : true), + isAlphaPremultiplied, trans, validateTransferType(transferType)); + + if (pixel_bits < 1 || pixel_bits > 32) { + // awt.236=The bits is less than 1 or greater than 32 + throw new IllegalArgumentException(Messages.getString("awt.236")); //$NON-NLS-1$ + } + + componentMasks = new int[numComponents]; + for (int i = 0; i < numColorComponents; i++) { + componentMasks[i] = colorMaskArray[i]; + } + + if (hasAlpha) { + componentMasks[numColorComponents] = alphaMask; + if (this.bits[numColorComponents] == 1) { + transparency = Transparency.BITMASK; + } + } + + parseComponents(); + } + + /** + * Instantiates a new packed color model. + * + * @param space + * the color space. + * @param bits + * the array of component masks. + * @param rmask + * the bitmask corresponding to the red band. + * @param gmask + * the bitmask corresponding to the green band. + * @param bmask + * the bitmask corresponding to the blue band. + * @param amask + * the bitmask corresponding to the alpha band. + * @param isAlphaPremultiplied + * whether the alpha is pre-multiplied in this color model. + * @param trans + * the transparency strategy, @see java.awt.Transparency. + * @param transferType + * the transfer type (primitive java type to use for the + * components). + * @throws IllegalArgumentException + * if the number of bits in the combined bitmasks for the color + * bands is less than one or greater than 32. + */ + public PackedColorModel(ColorSpace space, int bits, int rmask, int gmask, int bmask, int amask, + boolean isAlphaPremultiplied, int trans, int transferType) { + + super(bits, createBits(rmask, gmask, bmask, amask), space, (amask == 0 ? false : true), + isAlphaPremultiplied, trans, validateTransferType(transferType)); + + if (pixel_bits < 1 || pixel_bits > 32) { + // awt.236=The bits is less than 1 or greater than 32 + throw new IllegalArgumentException(Messages.getString("awt.236")); //$NON-NLS-1$ + } + + if (cs.getType() != ColorSpace.TYPE_RGB) { + // awt.239=The space is not a TYPE_RGB space + throw new IllegalArgumentException(Messages.getString("awt.239")); //$NON-NLS-1$ + } + + for (int i = 0; i < numColorComponents; i++) { + if (cs.getMinValue(i) != 0.0f || cs.getMaxValue(i) != 1.0f) { + // awt.23A=The min/max normalized component values are not + // 0.0/1.0 + throw new IllegalArgumentException(Messages.getString("awt.23A")); //$NON-NLS-1$ + } + } + componentMasks = new int[numComponents]; + componentMasks[0] = rmask; + componentMasks[1] = gmask; + componentMasks[2] = bmask; + + if (hasAlpha) { + componentMasks[3] = amask; + if (this.bits[3] == 1) { + transparency = Transparency.BITMASK; + } + } + + parseComponents(); + } + + @Override + public WritableRaster getAlphaRaster(WritableRaster raster) { + if (!hasAlpha) { + return null; + } + + int x = raster.getMinX(); + int y = raster.getMinY(); + int w = raster.getWidth(); + int h = raster.getHeight(); + int band[] = new int[1]; + band[0] = raster.getNumBands() - 1; + return raster.createWritableChild(x, y, w, h, x, y, band); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (!(obj instanceof PackedColorModel)) { + return false; + } + PackedColorModel cm = (PackedColorModel)obj; + + return (pixel_bits == cm.getPixelSize() && transferType == cm.getTransferType() + && cs.getType() == cm.getColorSpace().getType() && hasAlpha == cm.hasAlpha() + && isAlphaPremultiplied == cm.isAlphaPremultiplied() + && transparency == cm.getTransparency() + && numColorComponents == cm.getNumColorComponents() + && numComponents == cm.getNumComponents() + && Arrays.equals(bits, cm.getComponentSize()) && Arrays.equals(componentMasks, cm + .getMasks())); + } + + @Override + public boolean isCompatibleSampleModel(SampleModel sm) { + if (sm == null) { + return false; + } + if (!(sm instanceof SinglePixelPackedSampleModel)) { + return false; + } + SinglePixelPackedSampleModel esm = (SinglePixelPackedSampleModel)sm; + + return ((esm.getNumBands() == numComponents) && (esm.getTransferType() == transferType) && Arrays + .equals(esm.getBitMasks(), componentMasks)); + } + + @Override + public SampleModel createCompatibleSampleModel(int w, int h) { + return new SinglePixelPackedSampleModel(transferType, w, h, componentMasks); + } + + /** + * Gets the bitmask corresponding to the specified color component. + * + * @param index + * the index of the desired color. + * @return the mask. + */ + public final int getMask(int index) { + return componentMasks[index]; + } + + /** + * Gets the bitmasks of the components. + * + * @return the masks. + */ + public final int[] getMasks() { + return (componentMasks.clone()); + } + + /** + * Creates the bits. + * + * @param colorMaskArray + * the color mask array. + * @param alphaMask + * the alpha mask. + * @return the int[]. + */ + private static int[] createBits(int colorMaskArray[], int alphaMask) { + int bits[]; + int numComp; + if (alphaMask == 0) { + numComp = colorMaskArray.length; + } else { + numComp = colorMaskArray.length + 1; + } + + bits = new int[numComp]; + int i = 0; + for (; i < colorMaskArray.length; i++) { + bits[i] = countCompBits(colorMaskArray[i]); + if (bits[i] < 0) { + // awt.23B=The mask of the {0} component is not contiguous + throw new IllegalArgumentException(Messages.getString("awt.23B", i)); //$NON-NLS-1$ + } + } + + if (i < numComp) { + bits[i] = countCompBits(alphaMask); + + if (bits[i] < 0) { + // awt.23C=The mask of the alpha component is not contiguous + throw new IllegalArgumentException(Messages.getString("awt.23C")); //$NON-NLS-1$ + } + } + + return bits; + } + + /** + * Creates the bits. + * + * @param rmask + * the rmask. + * @param gmask + * the gmask. + * @param bmask + * the bmask. + * @param amask + * the amask. + * @return the int[]. + */ + private static int[] createBits(int rmask, int gmask, int bmask, int amask) { + + int numComp; + if (amask == 0) { + numComp = 3; + } else { + numComp = 4; + } + int bits[] = new int[numComp]; + + bits[0] = countCompBits(rmask); + if (bits[0] < 0) { + // awt.23D=The mask of the red component is not contiguous + throw new IllegalArgumentException(Messages.getString("awt.23D")); //$NON-NLS-1$ + } + + bits[1] = countCompBits(gmask); + if (bits[1] < 0) { + // awt.23E=The mask of the green component is not contiguous + throw new IllegalArgumentException(Messages.getString("awt.23E")); //$NON-NLS-1$ + } + + bits[2] = countCompBits(bmask); + if (bits[2] < 0) { + // awt.23F=The mask of the blue component is not contiguous + throw new IllegalArgumentException(Messages.getString("awt.23F")); //$NON-NLS-1$ + } + + if (amask != 0) { + bits[3] = countCompBits(amask); + if (bits[3] < 0) { + // awt.23C=The mask of the alpha component is not contiguous + throw new IllegalArgumentException(Messages.getString("awt.23C")); //$NON-NLS-1$ + } + } + + return bits; + } + + /** + * Count comp bits. + * + * @param compMask + * the comp mask. + * @return the int. + */ + private static int countCompBits(int compMask) { + int bits = 0; + if (compMask != 0) { + // Deleting final zeros + while ((compMask & 1) == 0) { + compMask >>>= 1; + } + // Counting component bits + while ((compMask & 1) == 1) { + compMask >>>= 1; + bits++; + } + } + + if (compMask != 0) { + return -1; + } + + return bits; + } + + /** + * Validate transfer type. + * + * @param transferType + * the transfer type. + * @return the int. + */ + private static int validateTransferType(int transferType) { + if (transferType != DataBuffer.TYPE_BYTE && transferType != DataBuffer.TYPE_USHORT + && transferType != DataBuffer.TYPE_INT) { + // awt.240=The transferType not is one of DataBuffer.TYPE_BYTE, + // DataBuffer.TYPE_USHORT or DataBuffer.TYPE_INT + throw new IllegalArgumentException(Messages.getString("awt.240")); //$NON-NLS-1$ + } + return transferType; + } + + /** + * Parses the components. + */ + private void parseComponents() { + offsets = new int[numComponents]; + scales = new float[numComponents]; + for (int i = 0; i < numComponents; i++) { + int off = 0; + int mask = componentMasks[i]; + while ((mask & 1) == 0) { + mask >>>= 1; + off++; + } + offsets[i] = off; + if (bits[i] == 0) { + scales[i] = 256.0f; // May be any value different from zero, + // because will dividing by zero + } else { + scales[i] = 255.0f / maxValues[i]; + } + } + + } + +} diff --git a/app/src/main/java/java/awt/image/PixelGrabber.java b/app/src/main/java/java/awt/image/PixelGrabber.java new file mode 100644 index 000000000..fd6a9fc21 --- /dev/null +++ b/app/src/main/java/java/awt/image/PixelGrabber.java @@ -0,0 +1,408 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package java.awt.image; + +import java.awt.Image; +import java.util.Hashtable; + +import org.apache.harmony.awt.internal.nls.Messages; + +public class PixelGrabber implements ImageConsumer { + + int width; + int height; + int X; + int Y; + int offset; + int scanline; + ImageProducer producer; + + byte bData[]; + int iData[]; + ColorModel cm; + + private int grabberStatus; + private int dataType; + private boolean isGrabbing; + private boolean isRGB; + + + private static final int DATA_TYPE_BYTE = 0; + private static final int DATA_TYPE_INT = 1; + private static final int DATA_TYPE_UNDEFINED = 2; + + private static final int ALL_BITS = (ImageObserver.FRAMEBITS | + ImageObserver.ALLBITS); + + private static final int GRABBING_STOP = ALL_BITS | ImageObserver.ERROR; + + + + public PixelGrabber(ImageProducer ip, int x, int y, int w, int h, int[] pix, + int off, int scansize) { + initialize(ip, x, y, w, h, pix, off, scansize, true); + } + + public PixelGrabber(Image img, int x, int y, int w, int h, int[] pix, + int off, int scansize) { + initialize(img.getSource(), x, y, w, h, pix, off, scansize, true); + } + + public PixelGrabber(Image img, int x, int y, int w, int h, boolean forceRGB) { + initialize(img.getSource(), x, y, w, h, null, 0, 0, forceRGB); + } + + public void setProperties(Hashtable props) { + return; + } + + public synchronized Object getPixels() { + switch(dataType){ + case DATA_TYPE_BYTE: + return bData; + case DATA_TYPE_INT: + return iData; + default: + return null; + } + } + + public void setColorModel(ColorModel model) { + return; + } + + public void setPixels(int srcX, int srcY, int srcW, int srcH, + ColorModel model, byte[] pixels, int srcOff, int srcScan) { + if(srcY < Y){ + int delta = Y - srcY; + if(delta >= height) { + return; + } + srcY += delta; + srcH -= delta; + srcOff += srcScan * delta; + } + + if(srcY + srcH > Y + height){ + srcH = Y + height - srcY; + if(srcH <= 0) { + return; + } + } + + if(srcX < X){ + int delta = X - srcX; + if(delta >= width) { + return; + } + srcW -= delta; + srcX += delta; + srcOff += delta; + } + + if(srcX + srcW > X + width){ + srcW = X + width - srcX; + if(srcW <= 0) { + return; + } + } + if(scanline == 0) { + scanline = width; + } + int realOff = offset + (srcY - Y) * scanline + (srcX - X); + switch(dataType){ + case DATA_TYPE_UNDEFINED: + cm = model; + if(model != ColorModel.getRGBdefault()){ + bData = new byte[width * height]; + isRGB = false; + dataType = DATA_TYPE_BYTE; + }else{ + iData = new int[width * height]; + isRGB = true; + dataType = DATA_TYPE_INT; + } + case DATA_TYPE_BYTE: + if(!isRGB && cm == model){ + for(int y = 0; y < srcH; y++){ + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(pixels, srcOff, bData, realOff, srcW); + srcOff += srcScan; + realOff += scanline; + } + break; + } + forceToRGB(); + case DATA_TYPE_INT: + for(int y = 0; y < srcH; y++){ + for(int x = 0; x < srcW; x++){ + iData[realOff + x] = cm.getRGB(pixels[srcOff + x] & 0xff); + } + srcOff += srcScan; + realOff += scanline; + } + } + + return; + } + + public void setPixels(int srcX, int srcY, int srcW, int srcH, + ColorModel model, int[] pixels, int srcOff, int srcScan) { + + if(srcY < Y){ + int delta = Y - srcY; + if(delta >= height) { + return; + } + srcY += delta; + srcH -= delta; + srcOff += srcScan * delta; + } + + if(srcY + srcH > Y + height){ + srcH = Y + height - srcY; + if(srcH <= 0) { + return; + } + } + + if(srcX < X){ + int delta = X - srcX; + if(delta >= width) { + return; + } + srcW -= delta; + srcX += delta; + srcOff += delta; + } + + if(srcX + srcW > X + width){ + srcW = X + width - srcX; + if(srcW <= 0) { + return; + } + } + if(scanline == 0) { + scanline = width; + } + int realOff = offset + (srcY - Y) * scanline + (srcX - X); + + int mask = 0xFF; + + switch(dataType){ + case DATA_TYPE_UNDEFINED: + cm = model; + iData = new int[width * height]; + dataType = DATA_TYPE_INT; + isRGB = (cm == ColorModel.getRGBdefault()); + + case DATA_TYPE_INT: + if(cm == model){ + for(int y = 0; y < srcH; y++){ + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(pixels, srcOff, iData, realOff, srcW); + srcOff += srcScan; + realOff += scanline; + } + break; + } + mask = 0xFFFFFFFF; + + case DATA_TYPE_BYTE: + forceToRGB(); + for(int y = 0; y < srcH; y++){ + for(int x = 0; x < srcW; x++){ + iData[realOff+x] = cm.getRGB(pixels[srcOff+x] & mask); + } + srcOff += srcScan; + realOff += scanline; + } + } + } + + public synchronized ColorModel getColorModel() { + return cm; + } + + public synchronized boolean grabPixels(long ms) + throws InterruptedException { + if((grabberStatus & GRABBING_STOP) != 0){ + return ((grabberStatus & ALL_BITS) != 0); + } + + long start = System.currentTimeMillis(); + + if(!isGrabbing){ + isGrabbing = true; + grabberStatus &= ~ImageObserver.ABORT; + producer.startProduction(this); + } + while((grabberStatus & GRABBING_STOP) == 0){ + if(ms != 0){ + ms = start + ms - System.currentTimeMillis(); + if(ms <= 0) { + break; + } + } + wait(ms); + } + + return ((grabberStatus & ALL_BITS) != 0); + } + + public void setDimensions(int w, int h) { + if(width < 0) { + width = w - X; + } + if(height < 0) { + height = h - Y; + } + + grabberStatus |= ImageObserver.WIDTH | ImageObserver.HEIGHT; + + if(width <=0 || height <=0){ + imageComplete(STATICIMAGEDONE); + return; + } + + if(isRGB && dataType == DATA_TYPE_UNDEFINED){ + iData = new int[width * height]; + dataType = DATA_TYPE_INT; + scanline = width; + } + } + + public void setHints(int hints) { + return; + } + + public synchronized void imageComplete(int status) { + switch(status){ + case IMAGEABORTED: + grabberStatus |= ImageObserver.ABORT; + break; + case IMAGEERROR: + grabberStatus |= ImageObserver.ERROR | ImageObserver.ABORT; + break; + case SINGLEFRAMEDONE: + grabberStatus |= ImageObserver.FRAMEBITS; + break; + case STATICIMAGEDONE: + grabberStatus |= ImageObserver.ALLBITS; + break; + default: + // awt.26A=Incorrect ImageConsumer completion status + throw new IllegalArgumentException(Messages.getString("awt.26A")); //$NON-NLS-1$ + } + isGrabbing = false; + producer.removeConsumer(this); + notifyAll(); + } + + public boolean grabPixels() throws InterruptedException { + return grabPixels(0); + } + + public synchronized void startGrabbing() { + if((grabberStatus & GRABBING_STOP) != 0){ + return; + } + if(!isGrabbing){ + isGrabbing = true; + grabberStatus &= ~ImageObserver.ABORT; + producer.startProduction(this); + } + } + + public synchronized void abortGrabbing() { + imageComplete(IMAGEABORTED); + } + + public synchronized int status() { + return grabberStatus; + } + + public synchronized int getWidth() { + if(width < 0) { + return -1; + } + return width; + } + + public synchronized int getStatus() { + return grabberStatus; + } + + public synchronized int getHeight() { + if(height < 0) { + return -1; + } + return height; + } + + private void initialize(ImageProducer ip, int x, int y, int w, int h, + int pixels[], int off, int scansize, boolean forceRGB){ + + producer = ip; + X = x; + Y = y; + width = w; + height = h; + iData = pixels; + dataType = (pixels == null) ? DATA_TYPE_UNDEFINED : DATA_TYPE_INT; + offset = off; + scanline = scansize; + if(forceRGB){ + cm = ColorModel.getRGBdefault(); + isRGB = true; + } + } + + /** + * Force pixels to INT RGB mode + */ + private void forceToRGB(){ + if (isRGB) + return; + + switch(dataType){ + case DATA_TYPE_BYTE: + iData = new int[width * height]; + for(int i = 0; i < iData.length; i++){ + iData[i] = cm.getRGB(bData[i] & 0xff); + } + dataType = DATA_TYPE_INT; + bData = null; + break; + + case DATA_TYPE_INT: + int buff[] = new int[width * height]; + for(int i = 0; i < iData.length; i++){ + buff[i] = cm.getRGB(iData[i]); + } + iData = buff; + break; + } + offset = 0; + scanline = width; + cm = ColorModel.getRGBdefault(); + isRGB = true; + } + +} diff --git a/app/src/main/java/java/awt/image/PixelInterleavedSampleModel.java b/app/src/main/java/java/awt/image/PixelInterleavedSampleModel.java new file mode 100644 index 000000000..8e646f80b --- /dev/null +++ b/app/src/main/java/java/awt/image/PixelInterleavedSampleModel.java @@ -0,0 +1,134 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The PixelInterleavedSampleModel class represents image data as represented as + * interleaved pixels and for which each sample of a pixel takes one data + * element of the DataBuffer. + * + * @since Android 1.0 + */ +public class PixelInterleavedSampleModel extends ComponentSampleModel { + + /** + * Instantiates a new PixelInterleavedSampleModel with the specified + * parameters. + * + * @param dataType + * the data type of the samples. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param pixelStride + * the pixel stride of the image data. + * @param scanlineStride + * the scanline stride of the of the image data. + * @param bandOffsets + * the array of the band offsets. + */ + public PixelInterleavedSampleModel(int dataType, int w, int h, int pixelStride, + int scanlineStride, int bandOffsets[]) { + + super(dataType, w, h, pixelStride, scanlineStride, bandOffsets); + + int maxOffset = bandOffsets[0]; + int minOffset = bandOffsets[0]; + for (int i = 1; i < bandOffsets.length; i++) { + if (bandOffsets[i] > maxOffset) { + maxOffset = bandOffsets[i]; + } + if (bandOffsets[i] < minOffset) { + minOffset = bandOffsets[i]; + } + } + + maxOffset -= minOffset; + + if (maxOffset > scanlineStride) { + // awt.241=Any offset between bands is greater than the Scanline + // stride + throw new IllegalArgumentException(Messages.getString("awt.241")); //$NON-NLS-1$ + } + + if (maxOffset > pixelStride) { + // awt.242=Pixel stride is less than any offset between bands + throw new IllegalArgumentException(Messages.getString("awt.242")); //$NON-NLS-1$ + } + + if (pixelStride * w > scanlineStride) { + // awt.243=Product of Pixel stride and w is greater than Scanline + // stride + throw new IllegalArgumentException(Messages.getString("awt.243")); //$NON-NLS-1$ + } + + } + + @Override + public SampleModel createSubsetSampleModel(int bands[]) { + int newOffsets[] = new int[bands.length]; + for (int i = 0; i < bands.length; i++) { + newOffsets[i] = bandOffsets[bands[i]]; + } + + return new PixelInterleavedSampleModel(dataType, width, height, pixelStride, + scanlineStride, newOffsets); + } + + @Override + public SampleModel createCompatibleSampleModel(int w, int h) { + int newOffsets[]; + int minOffset = bandOffsets[0]; + + for (int i = 1; i < numBands; i++) { + if (bandOffsets[i] < minOffset) { + minOffset = bandOffsets[i]; + } + } + + if (minOffset > 0) { + newOffsets = new int[numBands]; + for (int i = 0; i < numBands; i++) { + newOffsets[i] = bandOffsets[i] - minOffset; + } + } else { + newOffsets = bandOffsets; + } + + return new PixelInterleavedSampleModel(dataType, w, h, pixelStride, pixelStride * w, + newOffsets); + } + + @Override + public int hashCode() { + int hash = super.hashCode(); + int tmp = hash >>> 8; + hash <<= 8; + hash |= tmp; + + return hash ^ 0x66; + } + +} diff --git a/app/src/main/java/java/awt/image/RGBImageFilter.java b/app/src/main/java/java/awt/image/RGBImageFilter.java new file mode 100644 index 000000000..f5fe5d9ff --- /dev/null +++ b/app/src/main/java/java/awt/image/RGBImageFilter.java @@ -0,0 +1,195 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +/** + * The RGBImageFilter class represents a filter which modifies pixels of an + * image in the default RGB ColorModel. + * + * @since Android 1.0 + */ +public abstract class RGBImageFilter extends ImageFilter { + + /** + * The original model is the ColorModel to be replaced by the new model when + * substituteColorModel is called. + */ + protected ColorModel origmodel; + + /** + * The new model is the ColorModel with which to replace the original model + * when substituteColorModel is called. + */ + protected ColorModel newmodel; + + /** + * The canFilterIndexColorModel indicates if it is acceptable to apply the + * color filtering of the filterRGB method to the color table entries of an + * IndexColorModel object. + */ + protected boolean canFilterIndexColorModel; + + /** + * Instantiates a new RGBImageFilter. + */ + public RGBImageFilter() { + } + + /** + * Filters an IndexColorModel object by calling filterRGB function for each + * entry of IndexColorModel. + * + * @param icm + * the IndexColorModel to be filtered. + * @return the IndexColorModel. + */ + public IndexColorModel filterIndexColorModel(IndexColorModel icm) { + int transferType = icm.getTransferType(); + int bits = icm.getPixelSize(); + int mapSize = icm.getMapSize(); + int colorMap[] = new int[mapSize]; + int filteredColorMap[] = new int[mapSize]; + icm.getRGBs(colorMap); + int trans = -1; + boolean hasAlpha = false; + for (int i = 0; i < mapSize; i++) { + filteredColorMap[i] = filterRGB(-1, -1, colorMap[i]); + int alpha = filteredColorMap[i] >>> 24; + if (alpha != 0xff) { + if (!hasAlpha) { + hasAlpha = true; + } + if (alpha == 0 && trans < 0) { + trans = i; + } + } + } + + return new IndexColorModel(bits, mapSize, filteredColorMap, 0, hasAlpha, trans, + transferType); + } + + /** + * Replaces the original color model and the new one. + * + * @param oldcm + * the old ColorModel. + * @param newcm + * the new ColorModel. + */ + public void substituteColorModel(ColorModel oldcm, ColorModel newcm) { + origmodel = oldcm; + newmodel = newcm; + } + + @Override + public void setColorModel(ColorModel model) { + if (model instanceof IndexColorModel && canFilterIndexColorModel) { + IndexColorModel icm = (IndexColorModel)model; + ColorModel filteredModel = filterIndexColorModel(icm); + substituteColorModel(model, filteredModel); + consumer.setColorModel(filteredModel); + } else { + consumer.setColorModel(ColorModel.getRGBdefault()); + } + } + + @Override + public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off, + int scansize) { + + if (model == null || model == origmodel) { + consumer.setPixels(x, y, w, h, newmodel, pixels, off, scansize); + } else { + int rgbPixels[] = new int[w]; + for (int sy = y, pixelsOff = off; sy < y + h; sy++, pixelsOff += scansize) { + + for (int sx = x, idx = 0; sx < x + w; sx++, idx++) { + rgbPixels[idx] = model.getRGB(pixels[pixelsOff + idx]); + } + filterRGBPixels(x, sy, w, 1, rgbPixels, 0, w); + } + } + } + + @Override + public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, + int scansize) { + + if (model == null || model == origmodel) { + consumer.setPixels(x, y, w, h, newmodel, pixels, off, scansize); + } else { + int rgbPixels[] = new int[w]; + for (int sy = y, pixelsOff = off; sy < y + h; sy++, pixelsOff += scansize) { + + for (int sx = x, idx = 0; sx < x + w; sx++, idx++) { + rgbPixels[idx] = model.getRGB(pixels[pixelsOff + idx] & 0xff); + } + filterRGBPixels(x, sy, w, 1, rgbPixels, 0, w); + } + } + } + + /** + * Filters a region of pixels in the default RGB ColorModel by calling the + * filterRGB method for them. + * + * @param x + * the X coordinate of region. + * @param y + * the Y coordinate of region. + * @param w + * the width of region. + * @param h + * the height of region. + * @param pixels + * the pixels array. + * @param off + * the offset of array. + * @param scansize + * the distance between rows of pixels in the array. + */ + public void filterRGBPixels(int x, int y, int w, int h, int[] pixels, int off, int scansize) { + + for (int sy = y, lineOff = off; sy < y + h; sy++, lineOff += scansize) { + for (int sx = x, idx = 0; sx < x + w; sx++, idx++) { + pixels[lineOff + idx] = filterRGB(sx, sy, pixels[lineOff + idx]); + } + } + consumer.setPixels(x, y, w, h, ColorModel.getRGBdefault(), pixels, off, scansize); + } + + /** + * Converts a single input pixel in the default RGB ColorModel to a single + * output pixel. + * + * @param x + * the X pixel's coordinate. + * @param y + * the Y pixel's coordinate. + * @param rgb + * a pixel in the default RGB color model. + * @return a filtered pixel in the default RGB color model. + */ + public abstract int filterRGB(int x, int y, int rgb); + +} diff --git a/app/src/main/java/java/awt/image/Raster.java b/app/src/main/java/java/awt/image/Raster.java new file mode 100644 index 000000000..6749fde9e --- /dev/null +++ b/app/src/main/java/java/awt/image/Raster.java @@ -0,0 +1,1515 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.awt.Point; +import java.awt.Rectangle; + +import org.apache.harmony.awt.gl.image.OrdinaryWritableRaster; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Raster class represents a rectangular area of pixels. This class is + * defined by DataBuffer and SampleModel objects. The DataBuffer object stores + * sample values and DSampleModel defines the location of sample in this + * DataBuffer. + * + * @since Android 1.0 + */ +public class Raster { + + /** + * The DataBuffer of this Raster. + */ + protected DataBuffer dataBuffer; + + /** + * The height of this Raster. + */ + protected int height; + + /** + * The X coordinate of the upper left pixel in this Raster. + */ + protected int minX; + + /** + * The Y coordinate of the upper left pixel in this Raster. + */ + protected int minY; + + /** + * The number of bands in this Raster. + */ + protected int numBands; + + /** + * The number of data elements. + */ + protected int numDataElements; + + /** + * The parent of this Raster. + */ + protected Raster parent; + + /** + * The SampleModel of this Raster. + */ + protected SampleModel sampleModel; + + /** + * The X translation from the coordinate space of the SampleModel of this + * Raster. + */ + protected int sampleModelTranslateX; + + /** + * The Y translation from the coordinate space of the SampleModel of this + * Raster. + */ + protected int sampleModelTranslateY; + + /** + * The width of this Raster. + */ + protected int width; + + /** + * Creates a Raster object with a BandedSampleModel and the specified + * DataBuffer. The number of bands is defined by the length of bandOffsets + * or bankIndices arrays. + * + * @param dataBuffer + * the specified DataBuffer. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param scanlineStride + * the scanline stride of the image data. + * @param bankIndices + * the bank indices of bands. + * @param bandOffsets + * the band offsets of bands. + * @param location + * the location which defines the upper left corner of Raster. + * @return the WritableRaster object. + */ + public static WritableRaster createBandedRaster(DataBuffer dataBuffer, int w, int h, + int scanlineStride, int bankIndices[], int bandOffsets[], Point location) { + + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer + // overflow + throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ + } + + if (bankIndices == null || bandOffsets == null) { + // awt.277=bankIndices or bandOffsets is null + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.277")); //$NON-NLS-1$ + } + + if (dataBuffer == null) { + // awt.278=dataBuffer is null + throw new NullPointerException(Messages.getString("awt.278")); //$NON-NLS-1$ + } + + int dataType = dataBuffer.getDataType(); + + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT + && dataType != DataBuffer.TYPE_INT) { + // awt.230=dataType is not one of the supported data types + throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ + } + + BandedSampleModel sampleModel = new BandedSampleModel(dataType, w, h, scanlineStride, + bankIndices, bandOffsets); + + return new OrdinaryWritableRaster(sampleModel, dataBuffer, location); + } + + /** + * Creates a Raster object with a BandedSampleModel and the specified data + * type. The Data type can be one of the following values: TYPE_BYTE, + * TYPE_USHORT, or TYPE_INT. + * + * @param dataType + * the data type of the samples: TYPE_BYTE, TYPE_USHORT, or + * TYPE_INT. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param scanlineStride + * the scanline stride of the image data. + * @param bankIndices + * the bank indices of bands. + * @param bandOffsets + * the band offsets of bands. + * @param location + * the location which defines the upper left corner of the + * Raster. + * @return the WritableRaster object. + */ + public static WritableRaster createBandedRaster(int dataType, int w, int h, int scanlineStride, + int bankIndices[], int bandOffsets[], Point location) { + + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer + // overflow + throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ + } + + if (bankIndices == null || bandOffsets == null) { + // awt.277=bankIndices or bandOffsets is null + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.277")); //$NON-NLS-1$ + } + + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT + && dataType != DataBuffer.TYPE_INT) { + // awt.230=dataType is not one of the supported data types + throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ + } + + int maxOffset = bandOffsets[0]; + int maxBank = bankIndices[0]; + + for (int i = 0; i < bankIndices.length; i++) { + if (bandOffsets[i] > maxOffset) { + maxOffset = bandOffsets[i]; + } + if (bankIndices[i] > maxBank) { + maxBank = bankIndices[i]; + } + } + + int numBanks = maxBank + 1; + int dataSize = scanlineStride * (h - 1) + w + maxOffset; + + DataBuffer data = null; + + switch (dataType) { + case DataBuffer.TYPE_BYTE: + data = new DataBufferByte(dataSize, numBanks); + break; + case DataBuffer.TYPE_USHORT: + data = new DataBufferUShort(dataSize, numBanks); + break; + case DataBuffer.TYPE_INT: + data = new DataBufferInt(dataSize, numBanks); + break; + } + return createBandedRaster(data, w, h, scanlineStride, bankIndices, bandOffsets, location); + } + + /** + * Creates a Raster object with a BandedSampleModel and the specified data + * type. The Data type can be one of the following values: TYPE_BYTE, + * TYPE_USHORT, or TYPE_INT. + * + * @param dataType + * the data type of the samples: TYPE_BYTE, TYPE_USHORT, or + * TYPE_INT. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param bands + * the number of bands. + * @param location + * the location which defines the upper left corner of the + * Raster. + * @return the WritableRaster object. + */ + public static WritableRaster createBandedRaster(int dataType, int w, int h, int bands, + Point location) { + + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer + // overflow + throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ + } + + if (bands < 1) { + // awt.279=bands is less than 1 + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.279")); //$NON-NLS-1$ + } + + int bandOffsets[] = new int[bands]; + int bankIndices[] = new int[bands]; + + for (int i = 0; i < bands; i++) { + bandOffsets[i] = 0; + bankIndices[i] = i; + } + return createBandedRaster(dataType, w, h, w, bankIndices, bandOffsets, location); + } + + /** + * Creates a Raster object with a PixelInterleavedSampleModel and the + * specified DataBuffer. + * + * @param dataBuffer + * the DataBuffer. + * @param w + * the width of image data. + * @param h + * the height of image data. + * @param scanlineStride + * the scanline stride of the image data. + * @param pixelStride + * the pixel stride of image data. + * @param bandOffsets + * the band offsets of bands. + * @param location + * the location which defines the upper left corner of the + * Raster. + * @return the WritableRaster object. + */ + public static WritableRaster createInterleavedRaster(DataBuffer dataBuffer, int w, int h, + int scanlineStride, int pixelStride, int bandOffsets[], Point location) { + + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer + // overflow + throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ + } + + if (dataBuffer == null) { + // awt.278=dataBuffer is null + throw new NullPointerException(Messages.getString("awt.278")); //$NON-NLS-1$ + } + + int dataType = dataBuffer.getDataType(); + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT) { + // awt.230=dataType is not one of the supported data types + throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ + } + + if (dataBuffer.getNumBanks() > 1) { + // awt.27A=dataBuffer has more than one bank + throw new RasterFormatException(Messages.getString("awt.27A")); //$NON-NLS-1$ + } + + if (bandOffsets == null) { + // awt.27B=bandOffsets is null + throw new NullPointerException(Messages.getString("awt.27B")); //$NON-NLS-1$ + } + + PixelInterleavedSampleModel sampleModel = new PixelInterleavedSampleModel(dataType, w, h, + pixelStride, scanlineStride, bandOffsets); + + return new OrdinaryWritableRaster(sampleModel, dataBuffer, location); + + } + + /** + * Creates a Raster object with a PixelInterleavedSampleModel and the + * specified data type. The Data type can be one of the following values: + * TYPE_BYTE, TYPE_USHORT, or TYPE_INT. + * + * @param dataType + * the data type of the samples: TYPE_BYTE, TYPE_USHORT, or + * TYPE_INT. + * @param w + * the width of image data. + * @param h + * the height of image data. + * @param scanlineStride + * the scanline stride of the image data. + * @param pixelStride + * the pixel stride of image data. + * @param bandOffsets + * the band offsets of bands. + * @param location + * the location which defines the upper left corner of the + * Raster. + * @return the WritableRaster object. + */ + public static WritableRaster createInterleavedRaster(int dataType, int w, int h, + int scanlineStride, int pixelStride, int bandOffsets[], Point location) { + + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer + // overflow + throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ + } + + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT) { + // awt.230=dataType is not one of the supported data types + throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ + } + + if (bandOffsets == null) { + // awt.27B=bandOffsets is null + throw new NullPointerException(Messages.getString("awt.27B")); //$NON-NLS-1$ + } + + int minOffset = bandOffsets[0]; + for (int i = 1; i < bandOffsets.length; i++) { + if (bandOffsets[i] < minOffset) { + minOffset = bandOffsets[i]; + } + } + int size = (h - 1) * scanlineStride + w * pixelStride + minOffset; + DataBuffer data = null; + + switch (dataType) { + case DataBuffer.TYPE_BYTE: + data = new DataBufferByte(size); + break; + case DataBuffer.TYPE_USHORT: + data = new DataBufferUShort(size); + break; + } + + return createInterleavedRaster(data, w, h, scanlineStride, pixelStride, bandOffsets, + location); + } + + /** + * Creates a Raster object with a PixelInterleavedSampleModel and the + * specified data type. The Data type can be one of the following values: + * TYPE_BYTE, TYPE_USHORT, or TYPE_INT. + * + * @param dataType + * the data type of samples: TYPE_BYTE, TYPE_USHORT, or TYPE_INT. + * @param w + * the width of image data. + * @param h + * the height of image data. + * @param bands + * the number of bands. + * @param location + * the location which defines the upper left corner of the + * Raster. + * @return the WritableRaster. + */ + public static WritableRaster createInterleavedRaster(int dataType, int w, int h, int bands, + Point location) { + + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer + // overflow + throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ + } + + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT) { + // awt.230=dataType is not one of the supported data types + throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ + } + + int bandOffsets[] = new int[bands]; + for (int i = 0; i < bands; i++) { + bandOffsets[i] = i; + } + + return createInterleavedRaster(dataType, w, h, w * bands, bands, bandOffsets, location); + } + + /** + * Creates a Raster object with a SinglePixelPackedSampleModel and the + * specified DataBuffer. + * + * @param dataBuffer + * the DataBuffer. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param scanlineStride + * the scanline stride of the image data. + * @param bandMasks + * the band masks. + * @param location + * the location which defines the upper left corner of the + * Raster. + * @return the WritableRaster. + */ + public static WritableRaster createPackedRaster(DataBuffer dataBuffer, int w, int h, + int scanlineStride, int bandMasks[], Point location) { + if (dataBuffer == null) { + // awt.278=dataBuffer is null + throw new NullPointerException(Messages.getString("awt.278")); //$NON-NLS-1$ + } + + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer + // overflow + throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ + } + + if (bandMasks == null) { + // awt.27C=bandMasks is null + throw new RasterFormatException(Messages.getString("awt.27C")); //$NON-NLS-1$ + } + + if (dataBuffer.getNumBanks() > 1) { + // awt.27A=dataBuffer has more than one bank + throw new RasterFormatException(Messages.getString("awt.27A")); //$NON-NLS-1$ + } + + int dataType = dataBuffer.getDataType(); + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT + && dataType != DataBuffer.TYPE_INT) { + // awt.230=dataType is not one of the supported data types + throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ + } + + SinglePixelPackedSampleModel sampleModel = new SinglePixelPackedSampleModel(dataType, w, h, + scanlineStride, bandMasks); + + return new OrdinaryWritableRaster(sampleModel, dataBuffer, location); + } + + /** + * Creates a Raster object with a MultiPixelPackedSampleModel and the + * specified DataBuffer. + * + * @param dataBuffer + * the DataBuffer. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param bitsPerPixel + * the number of bits per pixel. + * @param location + * the location which defines the upper left corner of the + * Raster. + * @return the WritableRaster. + */ + public static WritableRaster createPackedRaster(DataBuffer dataBuffer, int w, int h, + int bitsPerPixel, Point location) { + + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer + // overflow + throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ + } + + if (dataBuffer == null) { + // awt.278=dataBuffer is null + throw new NullPointerException(Messages.getString("awt.278")); //$NON-NLS-1$ + } + + if (dataBuffer.getNumBanks() > 1) { + // awt.27A=dataBuffer has more than one bank + throw new RasterFormatException(Messages.getString("awt.27A")); //$NON-NLS-1$ + } + + int dataType = dataBuffer.getDataType(); + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT + && dataType != DataBuffer.TYPE_INT) { + // awt.230=dataType is not one of the supported data types + throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ + } + + MultiPixelPackedSampleModel sampleModel = new MultiPixelPackedSampleModel(dataType, w, h, + bitsPerPixel); + + return new OrdinaryWritableRaster(sampleModel, dataBuffer, location); + + } + + /** + * Creates a Raster object with a MultiPixelPackedSampleModel and the + * specified DataBuffer. + * + * @param dataType + * the data type of samples: TYPE_BYTE, TYPE_USHORT, or TYPE_INT. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param bands + * the number of bands. + * @param bitsPerBand + * the number of bits per band. + * @param location + * the location which defines the upper left corner of the + * Raster. + * @return the WritableRaster. + */ + public static WritableRaster createPackedRaster(int dataType, int w, int h, int bands, + int bitsPerBand, Point location) { + + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer + // overflow + throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ + } + + if (bands < 1 || bitsPerBand < 1) { + // awt.27D=bitsPerBand or bands is not greater than zero + throw new IllegalArgumentException(Messages.getString("awt.27D")); //$NON-NLS-1$ + } + + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT + && dataType != DataBuffer.TYPE_INT) { + // awt.230=dataType is not one of the supported data types + throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ + } + + if (bitsPerBand * bands > DataBuffer.getDataTypeSize(dataType)) { + // awt.27E=The product of bitsPerBand and bands is greater than the + // number of bits held by dataType + throw new IllegalArgumentException(Messages.getString("awt.27E")); //$NON-NLS-1$ + } + + if (bands > 1) { + + int bandMasks[] = new int[bands]; + int mask = (1 << bitsPerBand) - 1; + + for (int i = 0; i < bands; i++) { + bandMasks[i] = mask << (bitsPerBand * (bands - 1 - i)); + } + + return createPackedRaster(dataType, w, h, bandMasks, location); + } + DataBuffer data = null; + int size = ((bitsPerBand * w + DataBuffer.getDataTypeSize(dataType) - 1) / DataBuffer + .getDataTypeSize(dataType)) + * h; + + switch (dataType) { + case DataBuffer.TYPE_BYTE: + data = new DataBufferByte(size); + break; + case DataBuffer.TYPE_USHORT: + data = new DataBufferUShort(size); + break; + case DataBuffer.TYPE_INT: + data = new DataBufferInt(size); + break; + } + return createPackedRaster(data, w, h, bitsPerBand, location); + } + + /** + * Creates a Raster object with a SinglePixelPackedSampleModel and the + * specified DataBuffer. + * + * @param dataType + * the data type of samples: TYPE_BYTE, TYPE_USHORT, or TYPE_INT. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param bandMasks + * the band masks. + * @param location + * the location which defines the upper left corner of the + * Raster. + * @return the WritableRaster. + */ + public static WritableRaster createPackedRaster(int dataType, int w, int h, int bandMasks[], + Point location) { + + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT + && dataType != DataBuffer.TYPE_INT) { + // awt.230=dataType is not one of the supported data types + throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ + } + + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + if ((long)location.x + w > Integer.MAX_VALUE || (long)location.y + h > Integer.MAX_VALUE) { + // awt.276=location.x + w or location.y + h results in integer + // overflow + throw new RasterFormatException(Messages.getString("awt.276")); //$NON-NLS-1$ + } + + if (bandMasks == null) { + // awt.27C=bandMasks is null + throw new NullPointerException(Messages.getString("awt.27C")); //$NON-NLS-1$ + } + + DataBuffer data = null; + + switch (dataType) { + case DataBuffer.TYPE_BYTE: + data = new DataBufferByte(w * h); + break; + case DataBuffer.TYPE_USHORT: + data = new DataBufferUShort(w * h); + break; + case DataBuffer.TYPE_INT: + data = new DataBufferInt(w * h); + break; + } + + return createPackedRaster(data, w, h, w, bandMasks, location); + } + + /** + * Creates a Raster object with the specified DataBuffer and SampleModel. + * + * @param sm + * the specified SampleModel. + * @param db + * the specified DataBuffer. + * @param location + * the location which defines the upper left corner of the + * Raster. + * @return the Raster. + */ + public static Raster createRaster(SampleModel sm, DataBuffer db, Point location) { + + if (sm == null || db == null) { + // awt.27F=SampleModel or DataBuffer is null + throw new NullPointerException(Messages.getString("awt.27F")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + return new Raster(sm, db, location); + } + + /** + * Creates a WritableRaster with the specified SampleModel and DataBuffer. + * + * @param sm + * the specified SampleModel. + * @param db + * the specified DataBuffer. + * @param location + * the location which defines the upper left corner of the + * Raster. + * @return the WritableRaster. + */ + public static WritableRaster createWritableRaster(SampleModel sm, DataBuffer db, Point location) { + + if (sm == null || db == null) { + // awt.27F=SampleModel or DataBuffer is null + throw new NullPointerException(Messages.getString("awt.27F")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + return new OrdinaryWritableRaster(sm, db, location); + } + + /** + * Creates a WritableRaster with the specified SampleModel. + * + * @param sm + * the specified SampleModel. + * @param location + * the location which defines the upper left corner of the + * Raster. + * @return the WritableRaster. + */ + public static WritableRaster createWritableRaster(SampleModel sm, Point location) { + + if (sm == null) { + // awt.280=SampleModel is null + throw new NullPointerException(Messages.getString("awt.280")); //$NON-NLS-1$ + } + + if (location == null) { + location = new Point(0, 0); + } + + return createWritableRaster(sm, sm.createDataBuffer(), location); + } + + /** + * Instantiates a new Raster object with the specified SampleModel and + * DataBuffer. + * + * @param sampleModel + * the specified SampleModel. + * @param dataBuffer + * the specified DataBuffer. + * @param origin + * the specified origin. + */ + protected Raster(SampleModel sampleModel, DataBuffer dataBuffer, Point origin) { + + this(sampleModel, dataBuffer, new Rectangle(origin.x, origin.y, sampleModel.getWidth(), + sampleModel.getHeight()), origin, null); + } + + /** + * Instantiates a new Raster object with the specified SampleModel, + * DataBuffer, rectangular region and parent Raster. + * + * @param sampleModel + * the specified SampleModel. + * @param dataBuffer + * the specified DataBuffer. + * @param aRegion + * the a rectangular region which defines the new image bounds. + * @param sampleModelTranslate + * this point defines the translation point from the SampleModel + * coordinates to the new Raster coordinates. + * @param parent + * the parent of this Raster. + */ + protected Raster(SampleModel sampleModel, DataBuffer dataBuffer, Rectangle aRegion, + Point sampleModelTranslate, Raster parent) { + + if (sampleModel == null || dataBuffer == null || aRegion == null + || sampleModelTranslate == null) { + // awt.281=sampleModel, dataBuffer, aRegion or sampleModelTranslate + // is null + throw new NullPointerException(Messages.getString("awt.281")); //$NON-NLS-1$ + } + + if (aRegion.width <= 0 || aRegion.height <= 0) { + // awt.282=aRegion has width or height less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.282")); //$NON-NLS-1$ + } + + if ((long)aRegion.x + (long)aRegion.width > Integer.MAX_VALUE) { + // awt.283=Overflow X coordinate of Raster + throw new RasterFormatException(Messages.getString("awt.283")); //$NON-NLS-1$ + } + + if ((long)aRegion.y + (long)aRegion.height > Integer.MAX_VALUE) { + // awt.284=Overflow Y coordinate of Raster + throw new RasterFormatException(Messages.getString("awt.284")); //$NON-NLS-1$ + } + + if (sampleModel instanceof ComponentSampleModel) { + validateDataBuffer(dataBuffer, aRegion.width, aRegion.height, + ((ComponentSampleModel)sampleModel).getScanlineStride()); + } else if (sampleModel instanceof MultiPixelPackedSampleModel) { + validateDataBuffer(dataBuffer, aRegion.width, aRegion.height, + ((MultiPixelPackedSampleModel)sampleModel).getScanlineStride()); + } else if (sampleModel instanceof SinglePixelPackedSampleModel) { + validateDataBuffer(dataBuffer, aRegion.width, aRegion.height, + ((SinglePixelPackedSampleModel)sampleModel).getScanlineStride()); + } + + this.sampleModel = sampleModel; + this.dataBuffer = dataBuffer; + this.minX = aRegion.x; + this.minY = aRegion.y; + this.width = aRegion.width; + this.height = aRegion.height; + this.sampleModelTranslateX = sampleModelTranslate.x; + this.sampleModelTranslateY = sampleModelTranslate.y; + this.parent = parent; + this.numBands = sampleModel.getNumBands(); + this.numDataElements = sampleModel.getNumDataElements(); + + } + + /** + * Instantiates a new Raster with the specified SampleModel. + * + * @param sampleModel + * the specified SampleModel. + * @param origin + * the origin. + */ + protected Raster(SampleModel sampleModel, Point origin) { + this(sampleModel, sampleModel.createDataBuffer(), new Rectangle(origin.x, origin.y, + sampleModel.getWidth(), sampleModel.getHeight()), origin, null); + } + + /** + * Creates the child of this Raster by sharing the specified rectangular + * area in this raster. The parentX, parentY, width and height parameters + * specify the rectangular area to be shared. + * + * @param parentX + * the X coordinate of the upper left corner of this Raster. + * @param parentY + * the Y coordinate of the upper left corner of this Raster. + * @param width + * the width of the child area. + * @param height + * the height of the child area. + * @param childMinX + * the X coordinate of child area mapped to the parentX + * coordinate. + * @param childMinY + * the Y coordinate of child area mapped to the parentY + * coordinate. + * @param bandList + * the array of band indices. + * @return the Raster. + */ + public Raster createChild(int parentX, int parentY, int width, int height, int childMinX, + int childMinY, int bandList[]) { + if (width <= 0 || height <= 0) { + // awt.285=Width or Height of child Raster is less than or equal to + // zero + throw new RasterFormatException(Messages.getString("awt.285")); //$NON-NLS-1$ + } + + if (parentX < this.minX || parentX + width > this.minX + this.width) { + // awt.286=parentX disposes outside Raster + throw new RasterFormatException(Messages.getString("awt.286")); //$NON-NLS-1$ + } + + if (parentY < this.minY || parentY + height > this.minY + this.height) { + // awt.287=parentY disposes outside Raster + throw new RasterFormatException(Messages.getString("awt.287")); //$NON-NLS-1$ + } + + if ((long)parentX + width > Integer.MAX_VALUE) { + // awt.288=parentX + width results in integer overflow + throw new RasterFormatException(Messages.getString("awt.288")); //$NON-NLS-1$ + } + + if ((long)parentY + height > Integer.MAX_VALUE) { + // awt.289=parentY + height results in integer overflow + throw new RasterFormatException(Messages.getString("awt.289")); //$NON-NLS-1$ + } + + if ((long)childMinX + width > Integer.MAX_VALUE) { + // awt.28A=childMinX + width results in integer overflow + throw new RasterFormatException(Messages.getString("awt.28A")); //$NON-NLS-1$ + } + + if ((long)childMinY + height > Integer.MAX_VALUE) { + // awt.28B=childMinY + height results in integer overflow + throw new RasterFormatException(Messages.getString("awt.28B")); //$NON-NLS-1$ + } + + SampleModel childModel; + + if (bandList == null) { + childModel = sampleModel; + } else { + childModel = sampleModel.createSubsetSampleModel(bandList); + } + + int childTranslateX = childMinX - parentX; + int childTranslateY = childMinY - parentY; + + return new Raster(childModel, dataBuffer, + new Rectangle(childMinX, childMinY, width, height), new Point(childTranslateX + + sampleModelTranslateX, childTranslateY + sampleModelTranslateY), this); + } + + /** + * Create a compatible WritableRaster with the same parameters as this + * Raster. + * + * @return the WritableRaster. + */ + public WritableRaster createCompatibleWritableRaster() { + return new OrdinaryWritableRaster(sampleModel, new Point(0, 0)); + } + + /** + * Create a compatible WritableRaster with the same parameters as this + * Raster and the specified size. + * + * @param w + * the width of the new WritableRaster. + * @param h + * the height of the new WritableRaster. + * @return the WritableRaster. + */ + public WritableRaster createCompatibleWritableRaster(int w, int h) { + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new RasterFormatException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + SampleModel sm = sampleModel.createCompatibleSampleModel(w, h); + + return new OrdinaryWritableRaster(sm, new Point(0, 0)); + } + + /** + * Create a compatible WritableRaster with the same parameters as this + * Raster and the specified size and location. + * + * @param x + * the X coordinate of the new WritableRaster. + * @param y + * the Y coordinate of the new WritableRaster. + * @param w + * the width of the new WritableRaster. + * @param h + * the height of the new WritableRaster. + * @return the WritableRaster. + */ + public WritableRaster createCompatibleWritableRaster(int x, int y, int w, int h) { + + WritableRaster raster = createCompatibleWritableRaster(w, h); + + return raster.createWritableChild(0, 0, w, h, x, y, null); + } + + /** + * Create a compatible WritableRaster with the same parameters as this + * Raster and the specified rectangle which determines new WritableRaster's + * location and size. + * + * @param rect + * the specified Rectangle. + * @return the WritableRaster. + */ + public WritableRaster createCompatibleWritableRaster(Rectangle rect) { + if (rect == null) { + // awt.28C=Rect is null + throw new NullPointerException(Messages.getString("awt.28C")); //$NON-NLS-1$ + } + + return createCompatibleWritableRaster(rect.x, rect.y, rect.width, rect.height); + } + + /** + * Creates the translated child of this Raster. The New Raster object is a + * reference to the this Raster with a different location. + * + * @param childMinX + * the X coordinate of the new Raster. + * @param childMinY + * the Y coordinate of the new Raster. + * @return the Raster. + */ + public Raster createTranslatedChild(int childMinX, int childMinY) { + return createChild(minX, minY, width, height, childMinX, childMinY, null); + } + + /** + * Gets the bounds of this Raster as a rectangle. + * + * @return the bounds of this Raster. + */ + public Rectangle getBounds() { + return new Rectangle(minX, minY, width, height); + } + + /** + * Gets the DataBuffer associated with this Raster. + * + * @return the DataBuffer associated with this Raster. + */ + public DataBuffer getDataBuffer() { + return dataBuffer; + } + + /** + * Gets the data elements which represent the pixel data of the specified + * rectangle area as a primitive array. The following image data types are + * supported: DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, + * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or + * DataBuffer.TYPE_DOUBLE. + * + * @param x + * the X coordinate of the area of pixels. + * @param y + * the Y coordinate of the area of pixels. + * @param w + * the width of the area of pixels. + * @param h + * the height of the area of pixels. + * @param outData + * the resulting array. + * @return the data elements of the specified area of this Raster. + */ + public Object getDataElements(int x, int y, int w, int h, Object outData) { + return sampleModel.getDataElements(x - sampleModelTranslateX, y - sampleModelTranslateY, w, + h, outData, dataBuffer); + } + + /** + * Gets the data elements which represent the specified pixel of this Raster + * as a primitive array. The following image data types are supported: + * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, + * DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE. + * + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param outData + * the resulting data. + * @return the data elements of the specified pixel of this Raster. + */ + public Object getDataElements(int x, int y, Object outData) { + return sampleModel.getDataElements(x - sampleModelTranslateX, y - sampleModelTranslateY, + outData, dataBuffer); + } + + /** + * Gets the height of this Raster. + * + * @return the height of this Raster. + */ + public final int getHeight() { + return height; + } + + /** + * Gets the minimum X coordinate of this Raster. + * + * @return the minimum X coordinate of this Raster. + */ + public final int getMinX() { + return minX; + } + + /** + * Gets the minimum Y coordinate of this Raster. + * + * @return the minimum Y coordinate of this Raster. + */ + public final int getMinY() { + return minY; + } + + /** + * Gets the number of bands in this Raster. + * + * @return the number of bands in this Raster. + */ + public final int getNumBands() { + return numBands; + } + + /** + * Gets the number of data elements for one pixel. + * + * @return the number of data elements for one pixel. + */ + public final int getNumDataElements() { + return numDataElements; + } + + /** + * Gets the parent Raster for this Raster object. + * + * @return the parent Raster for this Raster object. + */ + public Raster getParent() { + return parent; + } + + /** + * Gets a double array of samples for the specified pixel in this Raster. + * + * @param x + * the pixel's X coordinate. + * @param y + * the pixel's Y coordinate. + * @param dArray + * the double array where result array will be stored. + * @return the double array of samples for the specified pixel in this + * Raster. + */ + public double[] getPixel(int x, int y, double dArray[]) { + return sampleModel.getPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, dArray, + dataBuffer); + } + + /** + * Gets a float array of samples for the specified pixel in this Raster. + * + * @param x + * the pixel's X coordinate. + * @param y + * the pixel's Y coordinate. + * @param fArray + * the float array where the result array will be stored. + * @return the float array of samples for the specified pixel in this + * Raster. + */ + public float[] getPixel(int x, int y, float fArray[]) { + return sampleModel.getPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, fArray, + dataBuffer); + } + + /** + * Gets an integer array of samples for the specified pixel in this Raster. + * + * @param x + * the pixel's X coordinate. + * @param y + * the pixel's Y coordinate. + * @param iArray + * the integer array where the result array will be stored. + * @return the integer array of samples for the specified pixel in this + * Raster. + */ + public int[] getPixel(int x, int y, int iArray[]) { + return sampleModel.getPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, iArray, + dataBuffer); + } + + /** + * Gets an double array of samples for the specified rectangular area of + * pixels in this Raster. + * + * @param x + * the X coordinate of the area of pixels. + * @param y + * the Y coordinate of the area of pixels. + * @param w + * the width of the area of pixels. + * @param h + * the height of the area of pixels. + * @param dArray + * the resulting array. + * @return the double array of samples for the specified rectangular area of + * pixels in this Raster. + */ + public double[] getPixels(int x, int y, int w, int h, double dArray[]) { + return sampleModel.getPixels(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, + dArray, dataBuffer); + } + + /** + * Gets an float array of samples for the specified rectangular area of + * pixels in this Raster. + * + * @param x + * the X coordinate of the area of pixels. + * @param y + * the Y coordinate of the area of pixels. + * @param w + * the width of the area of pixels. + * @param h + * the height of the area of pixels. + * @param fArray + * the resulting array. + * @return the float array of samples for the specified rectangular area of + * pixels in this Raster. + */ + public float[] getPixels(int x, int y, int w, int h, float fArray[]) { + return sampleModel.getPixels(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, + fArray, dataBuffer); + } + + /** + * Gets an integer array of samples for the specified rectangular area of + * pixels in this raster. + * + * @param x + * the X coordinate of the area of pixels. + * @param y + * the Y coordinate of the area of pixels. + * @param w + * the width of pixel's the area of pixels. + * @param h + * the height of pixel's the area of pixels. + * @param iArray + * the resulting array. + * @return the integer array of samples for the specified rectangular area + * of pixels in this Raster. + */ + public int[] getPixels(int x, int y, int w, int h, int iArray[]) { + return sampleModel.getPixels(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, + iArray, dataBuffer); + } + + /** + * Gets the sample for the specified band of the specified pixel as an + * integer. + * + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param b + * the band. + * @return the sample for the specified band of the specified pixel as an + * integer. + */ + public int getSample(int x, int y, int b) { + return sampleModel.getSample(x - sampleModelTranslateX, y - sampleModelTranslateY, b, + dataBuffer); + } + + /** + * Gets the sample for the specified band of the specified pixel as a + * double. + * + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param b + * the band. + * @return the sample for the specified band of the specified pixel as a + * double. + */ + public double getSampleDouble(int x, int y, int b) { + return sampleModel.getSampleDouble(x - sampleModelTranslateX, y - sampleModelTranslateY, b, + dataBuffer); + } + + /** + * Gets the sample for the specified band of the specified pixel as a float. + * + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param b + * the band. + * @return the sample for the specified band of the specified pixel as a + * float. + */ + public float getSampleFloat(int x, int y, int b) { + return sampleModel.getSampleFloat(x - sampleModelTranslateX, y - sampleModelTranslateY, b, + dataBuffer); + } + + /** + * Gets the SampleModel associated with this Raster. + * + * @return the SampleModel associated with this Raster. + */ + public SampleModel getSampleModel() { + return sampleModel; + } + + /** + * Gets the translation of the X coordinate from the SampleModel coordinate + * system to the Rasters's coordinate system. + * + * @return the value of the translation of the X coordinate from the + * SampleModel coordinate system to the Rasters's coordinate system. + */ + public final int getSampleModelTranslateX() { + return sampleModelTranslateX; + } + + /** + * Gets the translation of the Y coordinate from the SampleModel coordinate + * system to the Rasters's coordinate system. + * + * @return the value of the translation of the Y coordinate from the + * SampleModel coordinate system to the Rasters's coordinate system. + */ + public final int getSampleModelTranslateY() { + return sampleModelTranslateY; + } + + /** + * Gets the double array of samples for the specified band of the specified + * rectangular area of pixels in this Raster as a double array. + * + * @param x + * the X coordinate of the rectangular area of pixels. + * @param y + * the Y coordinate of the rectangular area of pixels. + * @param w + * the width of the rectangular area of pixels. + * @param h + * the height of the rectangular area of pixels. + * @param b + * the band. + * @param dArray + * the resulting double array. + * @return the double array of samples for the specified band of the + * specified rectangular area of pixels. + */ + public double[] getSamples(int x, int y, int w, int h, int b, double dArray[]) { + + return sampleModel.getSamples(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, + b, dArray, dataBuffer); + } + + /** + * Gets the float array of samples for the specified band of the specified + * rectangular area of pixels in this Raster as a float array. + * + * @param x + * the X coordinate of the rectangular area of pixels. + * @param y + * the Y coordinate of the rectangular area of pixels. + * @param w + * the width of the rectangular area of pixels. + * @param h + * the height of the rectangular area of pixels. + * @param b + * the band. + * @param fArray + * the resulting float array. + * @return the float array of samples for the specified band of the + * specified rectangular area of pixels. + */ + public float[] getSamples(int x, int y, int w, int h, int b, float fArray[]) { + + return sampleModel.getSamples(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, + b, fArray, dataBuffer); + } + + /** + * Gets the integer array of samples for the specified band of the specified + * rectangular area of pixels in this Raster as a integer array. + * + * @param x + * the X coordinate of the rectangular area of pixels. + * @param y + * the Y coordinate of the rectangular area of pixels. + * @param w + * the width of the rectangular area of pixels. + * @param h + * the height of the rectangular area of pixels. + * @param b + * the band. + * @param iArray + * the resulting integer array. + * @return the integer array of samples for the specified band of the + * specified rectangular area of pixels. + */ + public int[] getSamples(int x, int y, int w, int h, int b, int iArray[]) { + return sampleModel.getSamples(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, + b, iArray, dataBuffer); + } + + /** + * Gets the transfer type for pixels of this Raster. + * + * @see SampleModel#getTransferType() + * @return the transfer type for pixels of this Raster. + */ + public final int getTransferType() { + return sampleModel.getTransferType(); + } + + /** + * Gets the width of this Raster. + * + * @return the width of this Raster. + */ + public final int getWidth() { + return width; + } + + /** + * Validate data buffer. + * + * @param dataBuffer + * the data buffer. + * @param w + * the w. + * @param h + * the h. + * @param scanlineStride + * the scanline stride. + */ + private static void validateDataBuffer(final DataBuffer dataBuffer, final int w, final int h, + final int scanlineStride) { + if (dataBuffer.getSize() < (scanlineStride * (h - 1) + w - 1)) { + // awt.298=dataBuffer is too small + throw new RasterFormatException(Messages.getString("awt.298")); //$NON-NLS-1$ + } + } +} diff --git a/app/src/main/java/java/awt/image/RasterFormatException.java b/app/src/main/java/java/awt/image/RasterFormatException.java new file mode 100644 index 000000000..c667141ff --- /dev/null +++ b/app/src/main/java/java/awt/image/RasterFormatException.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +/** + * The RasterFormatException class represents the exception that is thrown when + * there's an invalid layout in the Raster. + * + * @since Android 1.0 + */ +public class RasterFormatException extends RuntimeException { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = 96598996116164315L; + + /** + * Instantiates a new RasterFormatException with the specified detail + * message. + * + * @param s + * the detail message. + */ + public RasterFormatException(String s) { + super(s); + } + +} diff --git a/app/src/main/java/java/awt/image/RasterOp.java b/app/src/main/java/java/awt/image/RasterOp.java new file mode 100644 index 000000000..19a84c9df --- /dev/null +++ b/app/src/main/java/java/awt/image/RasterOp.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey A. Petrenko + * @version $Revision$ + */ + +package java.awt.image; + +import java.awt.RenderingHints; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +/** + * The RasterOp interface provides methods for performing transformations from + * source data to destination data for Raster objects. The source and + * destination objects should contain the appropriate number of bands for the + * particular classes which implement this interface. + * + * @since Android 1.0 + */ +public interface RasterOp { + + /** + * Creates a destination WritableRaster with the specified Raster; this + * destination image data is empty and has the correct size and number of + * bands. + * + * @param src + * the source Raster. + * @return the WritableRaster. + */ + public WritableRaster createCompatibleDestRaster(Raster src); + + /** + * Performs a filter operation on the source Raster and stores the resulting + * image data to the destination WritableRaster. + * + * @param src + * the source Raster. + * @param dst + * the destination WritableRaster, where the result is stored. + * @return the filtered WritableRaster. + */ + public WritableRaster filter(Raster src, WritableRaster dst); + + /** + * Gets the bounds of the filtered Raster. + * + * @param src + * the source Raster to be filtered. + * @return the rectangle bounds of the filtered Raster. + */ + public Rectangle2D getBounds2D(Raster src); + + /** + * Gets the point of the destination image which corresponds to the + * specified point in the source raster. + * + * @param srcPoint + * the point of the source raster. + * @param dstPoint + * the point where the result will be stored. + * @return the destination point. + */ + public Point2D getPoint2D(Point2D srcPoint, Point2D dstPoint); + + /** + * Gets the RenderingHints of the RasterOp. + * + * @return the RenderingHints of the RasterOp. + */ + public RenderingHints getRenderingHints(); +} diff --git a/app/src/main/java/java/awt/image/RenderedImage.java b/app/src/main/java/java/awt/image/RenderedImage.java index 7a4ab6aa3..5eafa649a 100644 --- a/app/src/main/java/java/awt/image/RenderedImage.java +++ b/app/src/main/java/java/awt/image/RenderedImage.java @@ -1,5 +1,198 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + package java.awt.image; -public interface RenderedImage -{ +import java.awt.Rectangle; +import java.util.Vector; + +/** + * The RenderedImage interface should be implemented by all objects which + * contains image data. The image data is represented as a single tile or an + * array of tiles. + * + * @since Android 1.0 + */ +public interface RenderedImage { + + /** + * Gets the property with the specified name from the property set of this + * RenderedImage. + * + * @param name + * the property's name. + * @return the property value corresponded to this property's name. + */ + public Object getProperty(String name); + + /** + * Copies the region of this RenderedImage to the specified WritableRaster. + * The bounds of the region are the bounds of the WritableRaster. + * + * @param raster + * the WritableRaster. + * @return the created WritableRaster. + */ + public WritableRaster copyData(WritableRaster raster); + + /** + * Gets the image data of the image's region as one tile. + * + * @param rect + * the rectangular region of RenderedImage. + * @return the image data of the image's region as one tile. + */ + public Raster getData(Rectangle rect); + + /** + * Gets all RenderedImage objects which are the source of this RenderedImage + * object. + * + * @return a Vector of RenderedImage objects which are the source of this + * RenderedImage object or null, if there is no information about + * them. + */ + public Vector getSources(); + + /** + * Gets the set of all property names for this RenderedImage. + * + * @return the array of all property names for this RenderedImage. + */ + public String[] getPropertyNames(); + + /** + * Gets the SampleModel of this RenderedImage. + * + * @return the SampleModel of this RenderedImage. + */ + public SampleModel getSampleModel(); + + /** + * Gets the tile corresponded to the specified indices in the tile array. + * + * @param tileX + * the X index of the tile. + * @param tileY + * the Y index of the tile. + * @return the tile corresponded to the specified indices in the tile array. + */ + public Raster getTile(int tileX, int tileY); + + /** + * Gets the image data of this image as one tile. + * + * @return the image data of this image as one tile. + */ + public Raster getData(); + + /** + * Gets the ColorModel of this RenderedImage. + * + * @return the ColorModel of this RenderedImage. + */ + public ColorModel getColorModel(); + + /** + * Gets the width of the RenderedImage. + * + * @return the width of the RenderedImage. + */ + public int getWidth(); + + /** + * Gets the tile width. + * + * @return the tile width in pixels. + */ + public int getTileWidth(); + + /** + * Gets the tile height. + * + * @return the tile height in pixels. + */ + public int getTileHeight(); + + /** + * Gets the Y offset of the tile grid. + * + * @return the Y offset of the tile grid. + */ + public int getTileGridYOffset(); + + /** + * Gets the X offset of the tile grid. + * + * @return the X offset of the tile grid. + */ + public int getTileGridXOffset(); + + /** + * Gets the number of tiles along Y direction. + * + * @return the number of tiles along Y direction. + */ + public int getNumYTiles(); + + /** + * Gets the number of tiles along X direction. + * + * @return the number of tiles along X direction. + */ + public int getNumXTiles(); + + /** + * Gets the minimum Y coordinate of this RenderedImage. + * + * @return the minimum Y coordinate of this RenderedImage. + */ + public int getMinY(); + + /** + * Gets the minimum X coordinate of this RenderedImage. + * + * @return the minimum X coordinate of this RenderedImage. + */ + public int getMinX(); + + /** + * Gets the minimum tile's index along the Y direction. + * + * @return the minimum tile's index along the Y direction. + */ + public int getMinTileY(); + + /** + * Gets the minimum tile's index along the X direction. + * + * @return the minimum tile's index along the X direction. + */ + public int getMinTileX(); + + /** + * Gets the height of the RenderedImage. + * + * @return the height of the RenderedImage. + */ + public int getHeight(); + } diff --git a/app/src/main/java/java/awt/image/ReplicateScaleFilter.java b/app/src/main/java/java/awt/image/ReplicateScaleFilter.java new file mode 100644 index 000000000..51c0f4994 --- /dev/null +++ b/app/src/main/java/java/awt/image/ReplicateScaleFilter.java @@ -0,0 +1,225 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.util.Hashtable; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The ReplicateScaleFilter class scales an source image by replicating rows and + * columns of pixels to scale up or omitting rows and columns of pixels to scale + * down. + * + * @since Android 1.0 + */ +public class ReplicateScaleFilter extends ImageFilter { + + /** + * The width of a source image. + */ + protected int srcWidth; + + /** + * The height of a source image. + */ + protected int srcHeight; + + /** + * The width of a destination image. + */ + protected int destWidth; + + /** + * The height of a destination image. + */ + protected int destHeight; + + /** + * The integer array of source rows. + */ + protected int[] srcrows; + + /** + * The integer array of source columns. + */ + protected int[] srccols; + + /** + * An Object (byte array with a destination width) provides a row of pixel + * data to the ImageConsumer. + */ + protected Object outpixbuf; + + /** + * Instantiates a new ReplicateScaleFilter that filters the image with the + * specified width and height. + * + * @param width + * the width of scaled image. + * @param height + * the height of scaled image. + */ + public ReplicateScaleFilter(int width, int height) { + if (width == 0 || height == 0) { + // awt.234=Width or Height equals zero + throw new IllegalArgumentException(Messages.getString("awt.234")); //$NON-NLS-1$ + } + + this.destWidth = width; + this.destHeight = height; + } + + @SuppressWarnings("unchecked") + @Override + public void setProperties(Hashtable props) { + Hashtable fprops; + if (props == null) { + fprops = new Hashtable(); + } else { + fprops = (Hashtable)props.clone(); + } + String propName = "Rescale Filters"; //$NON-NLS-1$ + String prop = "destWidth=" + destWidth + "; " + //$NON-NLS-1$ //$NON-NLS-2$ + "destHeight=" + destHeight; //$NON-NLS-1$ + Object o = fprops.get(propName); + if (o != null) { + if (o instanceof String) { + prop = (String)o + "; " + prop; //$NON-NLS-1$ + } else { + prop = o.toString() + "; " + prop; //$NON-NLS-1$ + } + } + fprops.put(propName, prop); + consumer.setProperties(fprops); + } + + // setPixels methods produce pixels according to Java API Spacification + + @Override + public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off, + int scansize) { + + if (srccols == null) { + initArrays(); + } + int buff[]; + if (outpixbuf == null || !(outpixbuf instanceof int[])) { + buff = new int[destWidth]; + outpixbuf = buff; + } else { + buff = (int[])outpixbuf; + } + + int wa = (srcWidth - 1) >>> 1; + int ha = (srcHeight - 1) >>> 1; + int dstX = (x * destWidth + wa) / srcWidth; + int dstY = (y * destHeight + ha) / srcHeight; + + int sx, sy, dx, dy; + dy = dstY; + while ((dy < destHeight) && ((sy = srcrows[dy]) < y + h)) { + dx = dstX; + int srcOff = off + (sy - y) * scansize; + while ((dx < destWidth) && ((sx = srccols[dx]) < x + w)) { + buff[dx] = pixels[srcOff + (sx - x)]; + dx++; + } + + consumer.setPixels(dstX, dy, dx - dstX, 1, model, buff, dstX, destWidth); + dy++; + } + } + + @Override + public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, + int scansize) { + + if (srccols == null) { + initArrays(); + } + byte buff[]; + if (outpixbuf == null || !(outpixbuf instanceof byte[])) { + buff = new byte[destWidth]; + outpixbuf = buff; + } else { + buff = (byte[])outpixbuf; + } + + int wa = (srcWidth - 1) >>> 1; + int ha = (srcHeight - 1) >>> 1; + int dstX = (x * destWidth + wa) / srcWidth; + int dstY = (y * destHeight + ha) / srcHeight; + + int sx, sy, dx, dy; + dy = dstY; + while ((dy < destHeight) && ((sy = srcrows[dy]) < y + h)) { + dx = dstX; + int srcOff = off + (sy - y) * scansize; + while ((dx < destWidth) && ((sx = srccols[dx]) < x + w)) { + buff[dx] = pixels[srcOff + (sx - x)]; + dx++; + } + + consumer.setPixels(dstX, dy, dx - dstX, 1, model, buff, dstX, destWidth); + dy++; + } + } + + @Override + public void setDimensions(int w, int h) { + srcWidth = w; + srcHeight = h; + + if (destWidth < 0 && destHeight < 0) { + destWidth = srcWidth; + destHeight = srcHeight; + } else if (destWidth < 0) { + destWidth = destHeight * srcWidth / srcHeight; + } else if (destHeight < 0) { + destHeight = destWidth * srcHeight / srcWidth; + } + consumer.setDimensions(destWidth, destHeight); + } + + /** + * Initialization of srccols and srcrows arrays. + */ + private void initArrays() { + if ((destWidth < 0) || (destHeight < 0)) { + throw new IndexOutOfBoundsException(); + } + + srccols = new int[destWidth]; + int ca = srcWidth >>> 1; + for (int i = 0; i < destWidth; i++) { + srccols[i] = (i * srcWidth + ca) / destWidth; + } + + srcrows = new int[destHeight]; + int ra = srcHeight >>> 1; + for (int i = 0; i < destHeight; i++) { + srcrows[i] = (i * srcHeight + ra) / destHeight; + } + } + +} diff --git a/app/src/main/java/java/awt/image/RescaleOp.java b/app/src/main/java/java/awt/image/RescaleOp.java new file mode 100644 index 000000000..dbdf70e60 --- /dev/null +++ b/app/src/main/java/java/awt/image/RescaleOp.java @@ -0,0 +1,659 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + * + * @date: Oct 6, 2005 + */ + +package java.awt.image; + +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.*; +import java.util.Arrays; + +import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Class RescaleOp performs rescaling of the source image data by + * multiplying the pixel values with a scale factor and then adding an offset. + * + * @since Android 1.0 + */ +public class RescaleOp implements BufferedImageOp, RasterOp { + + /** + * The scale factors. + */ + private float scaleFactors[]; + + /** + * The offsets. + */ + private float offsets[]; + + /** + * The hints. + */ + private RenderingHints hints; + + static { + // TODO + // System.loadLibrary("imageops"); + } + + /** + * Instantiates a new RescaleOp object with the specified scale factors and + * offsets. + * + * @param scaleFactors + * the array of scale factor values. + * @param offsets + * the array of offset values. + * @param hints + * the RenderingHints or null. + */ + public RescaleOp(float[] scaleFactors, float[] offsets, RenderingHints hints) { + int numFactors = Math.min(scaleFactors.length, offsets.length); + + this.scaleFactors = new float[numFactors]; + this.offsets = new float[numFactors]; + + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(scaleFactors, 0, this.scaleFactors, 0, numFactors); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(offsets, 0, this.offsets, 0, numFactors); + + this.hints = hints; + } + + /** + * Instantiates a new RescaleOp object with the specified scale factor and + * offset. + * + * @param scaleFactor + * the scale factor. + * @param offset + * the offset. + * @param hints + * the RenderingHints or null. + */ + public RescaleOp(float scaleFactor, float offset, RenderingHints hints) { + scaleFactors = new float[1]; + offsets = new float[1]; + + scaleFactors[0] = scaleFactor; + offsets[0] = offset; + + this.hints = hints; + } + + /** + * Gets the number of scaling factors. + * + * @return the number of scaling factors. + */ + public final int getNumFactors() { + return scaleFactors.length; + } + + public final RenderingHints getRenderingHints() { + return hints; + } + + /** + * Gets the scale factors of this RescaleOp. + * + * @param scaleFactors + * the desired scale factors array will be copied to this array. + * @return the scale factors array. + */ + public final float[] getScaleFactors(float[] scaleFactors) { + if (scaleFactors == null) { + scaleFactors = new float[this.scaleFactors.length]; + } + + int minLength = Math.min(scaleFactors.length, this.scaleFactors.length); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(this.scaleFactors, 0, scaleFactors, 0, minLength); + return scaleFactors; + } + + /** + * Gets the offsets array of this RescaleOp. + * + * @param offsets + * the desired offsets array will be copied to this array. + * @return the offsets array of this RescaleOp. + */ + public final float[] getOffsets(float[] offsets) { + if (offsets == null) { + offsets = new float[this.offsets.length]; + } + + int minLength = Math.min(offsets.length, this.offsets.length); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(this.offsets, 0, offsets, 0, minLength); + return offsets; + } + + public final Point2D getPoint2D(Point2D srcPt, Point2D dstPt) { + if (dstPt == null) { + dstPt = new Point2D.Float(); + } + + dstPt.setLocation(srcPt); + return dstPt; + } + + public final Rectangle2D getBounds2D(Raster src) { + return src.getBounds(); + } + + public final Rectangle2D getBounds2D(BufferedImage src) { + return getBounds2D(src.getRaster()); + } + + public WritableRaster createCompatibleDestRaster(Raster src) { + return src.createCompatibleWritableRaster(); + } + + public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel dstCM) { + if (dstCM == null) { + dstCM = src.getColorModel(); + } + + if (dstCM instanceof IndexColorModel) { + dstCM = ColorModel.getRGBdefault(); + } + + WritableRaster r = dstCM.isCompatibleSampleModel(src.getSampleModel()) ? src.getRaster() + .createCompatibleWritableRaster(src.getWidth(), src.getHeight()) : dstCM + .createCompatibleWritableRaster(src.getWidth(), src.getHeight()); + + return new BufferedImage(dstCM, r, dstCM.isAlphaPremultiplied(), null); + } + + public final WritableRaster filter(Raster src, WritableRaster dst) { + if (dst == null) { + dst = createCompatibleDestRaster(src); + } else { + if (src.getNumBands() != dst.getNumBands()) { + // awt.21D=Number of src bands ({0}) does not match number of + // dst bands ({1}) + throw new IllegalArgumentException(Messages.getString("awt.21D", //$NON-NLS-1$ + src.getNumBands(), dst.getNumBands())); + } + } + + if (this.scaleFactors.length != 1 && this.scaleFactors.length != src.getNumBands()) { + // awt.21E=Number of scaling constants is not equal to the number of + // bands + throw new IllegalArgumentException(Messages.getString("awt.21E")); //$NON-NLS-1$ + } + + // TODO + // if (ippFilter(src, dst, BufferedImage.TYPE_CUSTOM, false) != 0) + if (slowFilter(src, dst, false) != 0) { + // awt.21F=Unable to transform source + throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$ + } + + return dst; + } + + /** + * Slow filter. + * + * @param src + * the src. + * @param dst + * the dst. + * @param skipAlpha + * the skip alpha. + * @return the int. + */ + private final int slowFilter(Raster src, WritableRaster dst, boolean skipAlpha) { + SampleModel sm = src.getSampleModel(); + + int numBands = src.getNumBands(); + int srcHeight = src.getHeight(); + int srcWidth = src.getWidth(); + + int srcMinX = src.getMinX(); + int srcMinY = src.getMinY(); + int dstMinX = dst.getMinX(); + int dstMinY = dst.getMinY(); + + int[] maxValues = new int[numBands]; + int[] masks = new int[numBands]; + int[] sampleSizes = sm.getSampleSize(); + + for (int i = 0; i < numBands; i++) { + maxValues[i] = (1 << sampleSizes[i]) - 1; + masks[i] = ~(maxValues[i]); + } + + // Processing bounds + float[] pixels = null; + pixels = src.getPixels(srcMinX, srcMinY, srcWidth, srcHeight, pixels); + + // Cycle over pixels to be calculated + if (skipAlpha) { // Always suppose that alpha channel is the last band + if (scaleFactors.length > 1) { + for (int i = 0; i < pixels.length;) { + for (int bandIdx = 0; bandIdx < numBands - 1; bandIdx++, i++) { + pixels[i] = pixels[i] * scaleFactors[bandIdx] + offsets[bandIdx]; + // Check for overflow now + if (((int)pixels[i] & masks[bandIdx]) != 0) { + if (pixels[i] < 0) { + pixels[i] = 0; + } else { + pixels[i] = maxValues[bandIdx]; + } + } + } + + i++; + } + } else { + for (int i = 0; i < pixels.length;) { + for (int bandIdx = 0; bandIdx < numBands - 1; bandIdx++, i++) { + pixels[i] = pixels[i] * scaleFactors[0] + offsets[0]; + // Check for overflow now + if (((int)pixels[i] & masks[bandIdx]) != 0) { + if (pixels[i] < 0) { + pixels[i] = 0; + } else { + pixels[i] = maxValues[bandIdx]; + } + } + } + + i++; + } + } + } else { + if (scaleFactors.length > 1) { + for (int i = 0; i < pixels.length;) { + for (int bandIdx = 0; bandIdx < numBands; bandIdx++, i++) { + pixels[i] = pixels[i] * scaleFactors[bandIdx] + offsets[bandIdx]; + // Check for overflow now + if (((int)pixels[i] & masks[bandIdx]) != 0) { + if (pixels[i] < 0) { + pixels[i] = 0; + } else { + pixels[i] = maxValues[bandIdx]; + } + } + } + } + } else { + for (int i = 0; i < pixels.length;) { + for (int bandIdx = 0; bandIdx < numBands; bandIdx++, i++) { + pixels[i] = pixels[i] * scaleFactors[0] + offsets[0]; + // Check for overflow now + if (((int)pixels[i] & masks[bandIdx]) != 0) { + if (pixels[i] < 0) { + pixels[i] = 0; + } else { + pixels[i] = maxValues[bandIdx]; + } + } + } + } + } + } + + dst.setPixels(dstMinX, dstMinY, srcWidth, srcHeight, pixels); + + return 0; + } + + public final BufferedImage filter(BufferedImage src, BufferedImage dst) { + ColorModel srcCM = src.getColorModel(); + + if (srcCM instanceof IndexColorModel) { + // awt.220=Source should not have IndexColorModel + throw new IllegalArgumentException(Messages.getString("awt.220")); //$NON-NLS-1$ + } + + // Check if the number of scaling factors matches the number of bands + int nComponents = srcCM.getNumComponents(); + boolean skipAlpha; + if (srcCM.hasAlpha()) { + if (scaleFactors.length == 1 || scaleFactors.length == nComponents - 1) { + skipAlpha = true; + } else if (scaleFactors.length == nComponents) { + skipAlpha = false; + } else { + // awt.21E=Number of scaling constants is not equal to the + // number of bands + throw new IllegalArgumentException(Messages.getString("awt.21E")); //$NON-NLS-1$ + } + } else if (scaleFactors.length == 1 || scaleFactors.length == nComponents) { + skipAlpha = false; + } else { + // awt.21E=Number of scaling constants is not equal to the number of + // bands + throw new IllegalArgumentException(Messages.getString("awt.21E")); //$NON-NLS-1$ + } + + BufferedImage finalDst = null; + if (dst == null) { + finalDst = dst; + dst = createCompatibleDestImage(src, srcCM); + } else if (!srcCM.equals(dst.getColorModel())) { + // Treat BufferedImage.TYPE_INT_RGB and BufferedImage.TYPE_INT_ARGB + // as same + if (!((src.getType() == BufferedImage.TYPE_INT_RGB || src.getType() == BufferedImage.TYPE_INT_ARGB) && (dst + .getType() == BufferedImage.TYPE_INT_RGB || dst.getType() == BufferedImage.TYPE_INT_ARGB))) { + finalDst = dst; + dst = createCompatibleDestImage(src, srcCM); + } + } + + // TODO + // if (ippFilter(src.getRaster(), dst.getRaster(), src.getType(), + // skipAlpha) != 0) + if (slowFilter(src.getRaster(), dst.getRaster(), skipAlpha) != 0) { + // awt.21F=Unable to transform source + throw new ImagingOpException(Messages.getString("awt.21F")); //$NON-NLS-1$ + } + + if (finalDst != null) { + Graphics2D g = finalDst.createGraphics(); + g.setComposite(AlphaComposite.Src); + g.drawImage(dst, 0, 0, null); + } else { + finalDst = dst; + } + + return finalDst; + } + + // Don't forget to pass allocated arrays for levels and values, size should + // be numBands*4 + /** + * Creates the levels. + * + * @param sm + * the sm. + * @param numBands + * the num bands. + * @param skipAlpha + * the skip alpha. + * @param levels + * the levels. + * @param values + * the values. + * @param channelsOrder + * the channels order. + */ + private final void createLevels(SampleModel sm, int numBands, boolean skipAlpha, int levels[], + int values[], int channelsOrder[]) { + // Suppose same sample size for all channels, otherwise use slow filter + int maxValue = (1 << sm.getSampleSize(0)) - 1; + + // For simplicity introduce these arrays + float extScaleFactors[] = new float[numBands]; + float extOffsets[] = new float[numBands]; + + if (scaleFactors.length != 1) { + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(scaleFactors, 0, extScaleFactors, 0, scaleFactors.length); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(offsets, 0, extOffsets, 0, scaleFactors.length); + } else { + for (int i = 0; i < numBands; i++) { + extScaleFactors[i] = scaleFactors[0]; + extOffsets[i] = offsets[0]; + } + } + + if (skipAlpha) { + extScaleFactors[numBands - 1] = 1; + extOffsets[numBands - 1] = 0; + } + + // Create a levels + for (int i = 0; i < numBands; i++) { + if (extScaleFactors[i] == 0) { + levels[i * 4] = 0; + levels[i * 4 + 1] = 0; + levels[i * 4 + 2] = maxValue + 1; + levels[i * 4 + 3] = maxValue + 1; + } + + float minLevel = -extOffsets[i] / extScaleFactors[i]; + float maxLevel = (maxValue - extOffsets[i]) / extScaleFactors[i]; + + if (minLevel < 0) { + minLevel = 0; + } else if (minLevel > maxValue) { + minLevel = maxValue; + } + + if (maxLevel < 0) { + maxLevel = 0; + } else if (maxLevel > maxValue) { + maxLevel = maxValue; + } + + levels[i * 4] = 0; + if (minLevel > maxLevel) { + levels[i * 4 + 1] = (int)maxLevel; + levels[i * 4 + 2] = (int)minLevel; + } else { + levels[i * 4 + 1] = (int)minLevel; + levels[i * 4 + 2] = (int)maxLevel; + } + levels[i * 4 + 3] = maxValue + 1; + + // Fill values + for (int k = 0; k < 4; k++) { + int idx = i * 4 + k; + values[idx] = (int)(extScaleFactors[i] * levels[idx] + extOffsets[i]); + if (values[idx] < 0) { + values[idx] = 0; + } else if (values[idx] > maxValue) { + values[idx] = maxValue; + } + } + } + + // Reorder data if channels are stored in different order + if (channelsOrder != null) { + int len = numBands * 4; + int savedLevels[] = new int[len]; + int savedValues[] = new int[len]; + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(levels, 0, savedLevels, 0, len); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(values, 0, savedValues, 0, len); + for (int i = 0; i < channelsOrder.length; i++) { + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(savedLevels, i * 4, levels, channelsOrder[i] * 4, 4); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(savedValues, i * 4, values, channelsOrder[i] * 4, 4); + } + } + } + + // TODO remove when this method is used + /** + * Ipp filter. + * + * @param src + * the src. + * @param dst + * the dst. + * @param imageType + * the image type. + * @param skipAlpha + * the skip alpha. + * @return the int. + */ + @SuppressWarnings("unused") + private final int ippFilter(Raster src, WritableRaster dst, int imageType, boolean skipAlpha) { + int res; + + int srcStride, dstStride; + int channels; + int offsets[] = null; + int channelsOrder[] = null; + + switch (imageType) { + case BufferedImage.TYPE_INT_ARGB: + case BufferedImage.TYPE_INT_ARGB_PRE: + case BufferedImage.TYPE_INT_RGB: { + channels = 4; + srcStride = src.getWidth() * 4; + dstStride = dst.getWidth() * 4; + channelsOrder = new int[] { + 2, 1, 0, 3 + }; + break; + } + + case BufferedImage.TYPE_4BYTE_ABGR: + case BufferedImage.TYPE_4BYTE_ABGR_PRE: + case BufferedImage.TYPE_INT_BGR: { + channels = 4; + srcStride = src.getWidth() * 4; + dstStride = dst.getWidth() * 4; + break; + } + + case BufferedImage.TYPE_BYTE_GRAY: { + channels = 1; + srcStride = src.getWidth(); + dstStride = dst.getWidth(); + break; + } + + case BufferedImage.TYPE_3BYTE_BGR: { + channels = 3; + srcStride = src.getWidth() * 3; + dstStride = dst.getWidth() * 3; + channelsOrder = new int[] { + 2, 1, 0 + }; + break; + } + + case BufferedImage.TYPE_USHORT_GRAY: + case BufferedImage.TYPE_USHORT_565_RGB: + case BufferedImage.TYPE_USHORT_555_RGB: + case BufferedImage.TYPE_BYTE_BINARY: { + return slowFilter(src, dst, skipAlpha); + } + + default: { + SampleModel srcSM = src.getSampleModel(); + SampleModel dstSM = dst.getSampleModel(); + + if (srcSM instanceof PixelInterleavedSampleModel + && dstSM instanceof PixelInterleavedSampleModel) { + // Check PixelInterleavedSampleModel + if (srcSM.getDataType() != DataBuffer.TYPE_BYTE + || dstSM.getDataType() != DataBuffer.TYPE_BYTE) { + return slowFilter(src, dst, skipAlpha); + } + + channels = srcSM.getNumBands(); // Have IPP functions for 1, + // 3 and 4 channels + if (!(channels == 1 || channels == 3 || channels == 4)) { + return slowFilter(src, dst, skipAlpha); + } + + srcStride = ((ComponentSampleModel)srcSM).getScanlineStride(); + dstStride = ((ComponentSampleModel)dstSM).getScanlineStride(); + + channelsOrder = ((ComponentSampleModel)srcSM).getBandOffsets(); + } else if (srcSM instanceof SinglePixelPackedSampleModel + && dstSM instanceof SinglePixelPackedSampleModel) { + // Check SinglePixelPackedSampleModel + SinglePixelPackedSampleModel sppsm1 = (SinglePixelPackedSampleModel)srcSM; + SinglePixelPackedSampleModel sppsm2 = (SinglePixelPackedSampleModel)dstSM; + + channels = sppsm1.getNumBands(); + + // TYPE_INT_RGB, TYPE_INT_ARGB... + if (sppsm1.getDataType() != DataBuffer.TYPE_INT + || sppsm2.getDataType() != DataBuffer.TYPE_INT + || !(channels == 3 || channels == 4)) { + return slowFilter(src, dst, skipAlpha); + } + + // Check compatibility of sample models + if (!Arrays.equals(sppsm1.getBitOffsets(), sppsm2.getBitOffsets()) + || !Arrays.equals(sppsm1.getBitMasks(), sppsm2.getBitMasks())) { + return slowFilter(src, dst, skipAlpha); + } + + for (int i = 0; i < channels; i++) { + if (sppsm1.getSampleSize(i) != 8) { + return slowFilter(src, dst, skipAlpha); + } + } + + channelsOrder = new int[channels]; + int bitOffsets[] = sppsm1.getBitOffsets(); + for (int i = 0; i < channels; i++) { + channelsOrder[i] = bitOffsets[i] / 8; + } + + if (channels == 3) { // Don't skip channel now, could be + // optimized + channels = 4; + } + + srcStride = sppsm1.getScanlineStride() * 4; + dstStride = sppsm2.getScanlineStride() * 4; + } else { + return slowFilter(src, dst, skipAlpha); + } + + // Fill offsets if there's a child raster + if (src.getParent() != null || dst.getParent() != null) { + if (src.getSampleModelTranslateX() != 0 || src.getSampleModelTranslateY() != 0 + || dst.getSampleModelTranslateX() != 0 + || dst.getSampleModelTranslateY() != 0) { + offsets = new int[4]; + offsets[0] = -src.getSampleModelTranslateX() + src.getMinX(); + offsets[1] = -src.getSampleModelTranslateY() + src.getMinY(); + offsets[2] = -dst.getSampleModelTranslateX() + dst.getMinX(); + offsets[3] = -dst.getSampleModelTranslateY() + dst.getMinY(); + } + } + } + } + + int levels[] = new int[4 * channels]; + int values[] = new int[4 * channels]; + + createLevels(src.getSampleModel(), channels, skipAlpha, levels, values, channelsOrder); + + Object srcData, dstData; + AwtImageBackdoorAccessor dbAccess = AwtImageBackdoorAccessor.getInstance(); + try { + srcData = dbAccess.getData(src.getDataBuffer()); + dstData = dbAccess.getData(dst.getDataBuffer()); + } catch (IllegalArgumentException e) { + return -1; // Unknown data buffer type + } + + res = LookupOp.ippLUT(srcData, src.getWidth(), src.getHeight(), srcStride, dstData, dst + .getWidth(), dst.getHeight(), dstStride, levels, values, channels, offsets, true); + + return res; + } +} diff --git a/app/src/main/java/java/awt/image/SampleModel.java b/app/src/main/java/java/awt/image/SampleModel.java new file mode 100644 index 000000000..c967fa6e9 --- /dev/null +++ b/app/src/main/java/java/awt/image/SampleModel.java @@ -0,0 +1,1166 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The SampleModel class is abstract class for retrieving pixel's samples in the + * data of an image. Each pixel contains several samples. A sample is the set of + * values of the bands for single pixel. For example, each pixel in the RGB + * model contains three samples and there are three corresponding bands in the + * image data of such pixels representing red, green and blue components. + *

+ * The image data is represented as a Raster with a DataBuffer and a + * SampleModel. The SampleModel allows access to the samples in the DataBuffer. + * + * @since Android 1.0 + */ +public abstract class SampleModel { + + /** + * The width of the image data which this SampleModel describes. + */ + protected int width; + + /** + * The height of the image data which this SampleModel describes. + */ + protected int height; + + /** + * The number of bands of image data which this SampleModel describes. + */ + protected int numBands; + + /** + * The data type of the image data which this SampleModel describes. + */ + protected int dataType; + + /** + * Instantiates a new SampleModel with the specified data type, width, + * height and number of bands. + * + * @param dataType + * the data type of the image data. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param numBands + * the number of bands of the image data. + */ + public SampleModel(int dataType, int w, int h, int numBands) { + if (w <= 0 || h <= 0) { + // awt.22E=w or h is less than or equal to zero + throw new IllegalArgumentException(Messages.getString("awt.22E")); //$NON-NLS-1$ + } + + double squre = ((double)w) * ((double)h); + if (squre >= Integer.MAX_VALUE) { + // awt.22F=The product of w and h is greater than Integer.MAX_VALUE + throw new IllegalArgumentException(Messages.getString("awt.22F")); //$NON-NLS-1$ + } + + if (dataType < DataBuffer.TYPE_BYTE || dataType > DataBuffer.TYPE_DOUBLE + && dataType != DataBuffer.TYPE_UNDEFINED) { + // awt.230=dataType is not one of the supported data types + throw new IllegalArgumentException(Messages.getString("awt.230")); //$NON-NLS-1$ + } + + if (numBands < 1) { + // awt.231=Number of bands must be more then 0 + throw new IllegalArgumentException(Messages.getString("awt.231")); //$NON-NLS-1$ + } + + this.dataType = dataType; + this.width = w; + this.height = h; + this.numBands = numBands; + + } + + /** + * Gets the data array for the specified pixel of the specified DataBuffer + * with one of the following types: DataBuffer.TYPE_BYTE, + * DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, + * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE. + * + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. + * @param obj + * the Object is a data where the result will be stored. + * @param data + * the image data. + * @return the data array for the specified pixel of the specified + * DataBuffer. + */ + public abstract Object getDataElements(int x, int y, Object obj, DataBuffer data); + + /** + * Gets the array of pixel data for the specified rectangular area of pixels + * of the specified DataBuffer with one of the following types: + * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, + * DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE. + * + * @param x + * the X coordinate of the rectangular pixel area. + * @param y + * the Y coordinate of the rectangular pixel area. + * @param w + * the width of the rectangular pixel area. + * @param h + * the height of the rectangular pixel area. + * @param obj + * the Object is an array with the primitive type, where the + * result array will be stored. + * @param data + * the image data. + * @return the array of pixel data for the specified rectangular area of + * pixels of the specified DataBuffer object. + */ + public Object getDataElements(int x, int y, int w, int h, Object obj, DataBuffer data) { + int numDataElements = getNumDataElements(); + int idx = 0; + + switch (getTransferType()) { + case DataBuffer.TYPE_BYTE: + byte bdata[]; + byte bbuf[] = null; + + if (obj == null) { + bdata = new byte[numDataElements * w * h]; + } else { + bdata = (byte[])obj; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + bbuf = (byte[])getDataElements(j, i, bbuf, data); + for (int n = 0; n < numDataElements; n++) { + bdata[idx++] = bbuf[n]; + } + } + } + obj = bdata; + break; + + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: + short sdata[]; + short sbuf[] = null; + + if (obj == null) { + sdata = new short[numDataElements * w * h]; + } else { + sdata = (short[])obj; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + sbuf = (short[])getDataElements(j, i, sbuf, data); + for (int n = 0; n < numDataElements; n++) { + sdata[idx++] = sbuf[n]; + } + } + } + obj = sdata; + break; + + case DataBuffer.TYPE_INT: + int idata[]; + int ibuf[] = null; + + if (obj == null) { + idata = new int[numDataElements * w * h]; + } else { + idata = (int[])obj; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + ibuf = (int[])getDataElements(j, i, ibuf, data); + for (int n = 0; n < numDataElements; n++) { + idata[idx++] = ibuf[n]; + } + } + } + obj = idata; + break; + + case DataBuffer.TYPE_FLOAT: + float fdata[]; + float fbuf[] = null; + + if (obj == null) { + fdata = new float[numDataElements * w * h]; + } else { + fdata = (float[])obj; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + fbuf = (float[])getDataElements(j, i, fbuf, data); + for (int n = 0; n < numDataElements; n++) { + fdata[idx++] = fbuf[n]; + } + } + } + obj = fdata; + break; + + case DataBuffer.TYPE_DOUBLE: + double ddata[]; + double dbuf[] = null; + + if (obj == null) { + ddata = new double[numDataElements * w * h]; + } else { + ddata = (double[])obj; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + dbuf = (double[])getDataElements(j, i, dbuf, data); + for (int n = 0; n < numDataElements; n++) { + ddata[idx++] = dbuf[n]; + } + } + } + obj = ddata; + break; + + } + + return obj; + } + + /** + * Sets the data for a single pixel in the specified DataBuffer from a + * primitive array with one of the following types: DataBuffer.TYPE_BYTE, + * DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, + * DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE. + * + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. + * @param obj + * the Object - the array of primitive pixel data to be set. + * @param data + * the image data. + */ + public abstract void setDataElements(int x, int y, Object obj, DataBuffer data); + + /** + * Sets the data elements for a rectangular area of pixels in the specified + * DataBuffer from a primitive array with one of the following types: + * DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, + * DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE. + * + * @param x + * the X coordinate of the specified rectangular area. + * @param y + * the Y coordinate of the specified rectangular area. + * @param w + * the width of rectangle. + * @param h + * the height of rectangle. + * @param obj + * the Object - the array of primitive pixel data to be set. + * @param data + * the image data. + */ + public void setDataElements(int x, int y, int w, int h, Object obj, DataBuffer data) { + int numDataElements = getNumDataElements(); + int idx = 0; + + switch (getTransferType()) { + case DataBuffer.TYPE_BYTE: + byte bbuf[] = new byte[numDataElements]; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numDataElements; n++) { + bbuf[n] = ((byte[])obj)[idx++]; + } + setDataElements(j, i, bbuf, data); + } + } + + break; + + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: + short sbuf[] = new short[numDataElements]; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numDataElements; n++) { + sbuf[n] = ((short[])obj)[idx++]; + } + setDataElements(j, i, sbuf, data); + } + } + break; + + case DataBuffer.TYPE_INT: + int ibuf[] = new int[numDataElements]; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numDataElements; n++) { + ibuf[n] = ((int[])obj)[idx++]; + } + setDataElements(j, i, ibuf, data); + } + } + break; + + case DataBuffer.TYPE_FLOAT: + float fbuf[] = new float[numDataElements]; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numDataElements; n++) { + fbuf[n] = ((float[])obj)[idx++]; + } + setDataElements(j, i, fbuf, data); + } + } + break; + + case DataBuffer.TYPE_DOUBLE: + double dbuf[] = new double[numDataElements]; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numDataElements; n++) { + dbuf[n] = ((double[])obj)[idx++]; + } + setDataElements(j, i, dbuf, data); + } + } + break; + + } + } + + /** + * Creates a new SampleModel with the specified bands of this SampleModel. + * + * @param bands + * the array of bands from this SampleModel. + * @return the SampleModel with the specified bands of this SampleModel. + */ + public abstract SampleModel createSubsetSampleModel(int bands[]); + + /** + * Creates the SampleModel which has the same data as in this SampleModel + * with a different width and height. + * + * @param a0 + * the width of the image data. + * @param a1 + * the height of the image data. + * @return the SampleModel which has the same data as in this SampleModel + * with a different width and height. + */ + public abstract SampleModel createCompatibleSampleModel(int a0, int a1); + + /** + * Gets the samples of the specified pixel as an integer array. + * + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. + * @param iArray + * the integer array where result will be stored. + * @param data + * the image data. + * @return the integer array with the samples of the specified pixel. + */ + public int[] getPixel(int x, int y, int iArray[], DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int pixel[]; + + if (iArray == null) { + pixel = new int[numBands]; + } else { + pixel = iArray; + } + + for (int i = 0; i < numBands; i++) { + pixel[i] = getSample(x, y, i, data); + } + + return pixel; + } + + /** + * Sets a pixel of the DataBuffer from a integer array of samples. + * + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. + * @param iArray + * the integer array. + * @param data + * the image data. + */ + public void setPixel(int x, int y, int iArray[], DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, iArray[i], data); + } + } + + /** + * Gets the samples of the specified pixel as a float array. + * + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. + * @param fArray + * the float array where result will be stored. + * @param data + * the image data. + * @return the float array with the samples of the specified pixel. + */ + public float[] getPixel(int x, int y, float fArray[], DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + float pixel[]; + + if (fArray == null) { + pixel = new float[numBands]; + } else { + pixel = fArray; + } + + for (int i = 0; i < numBands; i++) { + pixel[i] = getSampleFloat(x, y, i, data); + } + + return pixel; + } + + /** + * Sets a pixel of the DataBuffer from a float array of samples. + * + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. + * @param fArray + * the float array. + * @param data + * the image data. + */ + public void setPixel(int x, int y, float fArray[], DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, fArray[i], data); + } + } + + /** + * Gets the samples of the specified pixel as a double array. + * + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. + * @param dArray + * the double array where result will be stored. + * @param data + * the image data. + * @return the double array with the samples of the specified pixel. + */ + public double[] getPixel(int x, int y, double dArray[], DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + double pixel[]; + + if (dArray == null) { + pixel = new double[numBands]; + } else { + pixel = dArray; + } + + for (int i = 0; i < numBands; i++) { + pixel[i] = getSampleDouble(x, y, i, data); + } + + return pixel; + } + + /** + * Sets a pixel of the DataBuffer from a double array of samples. + * + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. + * @param dArray + * the double array. + * @param data + * the image data. + */ + public void setPixel(int x, int y, double dArray[], DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + for (int i = 0; i < numBands; i++) { + setSample(x, y, i, dArray[i], data); + } + } + + /** + * Gets the sample of a specified band for the specified pixel as an + * integer. + * + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. + * @param b + * the specified band. + * @param data + * the image data. + * @return the sample of a specified band for the specified pixel. + */ + public abstract int getSample(int x, int y, int b, DataBuffer data); + + /** + * Gets the sample of a specified band for the specified pixel as a float. + * + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. + * @param b + * the specified band. + * @param data + * the image data. + * @return the sample of a specified band for the specified pixel. + */ + public float getSampleFloat(int x, int y, int b, DataBuffer data) { + return getSample(x, y, b, data); + } + + /** + * Gets the sample of a specified band for the specified pixel as a double. + * + * @param x + * the X coordinate of pixel. + * @param y + * the Y coordinate of pixel. + * @param b + * the specified band. + * @param data + * the image data. + * @return the sample of a specified band for the specified pixel. + */ + public double getSampleDouble(int x, int y, int b, DataBuffer data) { + return getSample(x, y, b, data); + } + + /** + * Gets the samples of the specified rectangular area of pixels as an + * integer array. + * + * @param x + * the X coordinate of the rectangle of pixels. + * @param y + * the Y coordinate of the rectangle of pixels. + * @param w + * the width of the rectangle of pixels. + * @param h + * the height of the rectangle of pixels. + * @param iArray + * the integer array where result will be stored. + * @param data + * the image data. + * @return the integer array with the samples of the specified rectangular + * area of pixels. + */ + public int[] getPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) { + if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int pixels[]; + int idx = 0; + + if (iArray == null) { + pixels = new int[w * h * numBands]; + } else { + pixels = iArray; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numBands; n++) { + pixels[idx++] = getSample(j, i, n, data); + } + } + } + return pixels; + } + + /** + * Sets all of the samples for a rectangular area of pixels of the + * DataBuffer from an integer array. + * + * @param x + * the X coordinate of the rectangle of pixels. + * @param y + * the Y coordinate of the rectangle of pixels. + * @param w + * the width of the rectangle of pixels. + * @param h + * the height of the rectangle of pixels. + * @param iArray + * the integer array. + * @param data + * the image data. + */ + public void setPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) { + if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int idx = 0; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numBands; n++) { + setSample(j, i, n, iArray[idx++], data); + } + } + } + } + + /** + * Gets the samples of the specified rectangular area of pixels as a float + * array. + * + * @param x + * the X coordinate of the rectangle of pixels. + * @param y + * the Y coordinate of the rectangle of pixels. + * @param w + * the width of the rectangle of pixels. + * @param h + * the height of the rectangle of pixels. + * @param fArray + * the float array where result will be stored. + * @param data + * the image data. + * @return the float array with the samples of the specified rectangular + * area of pixels. + */ + public float[] getPixels(int x, int y, int w, int h, float fArray[], DataBuffer data) { + if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + float pixels[]; + int idx = 0; + + if (fArray == null) { + pixels = new float[w * h * numBands]; + } else { + pixels = fArray; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numBands; n++) { + pixels[idx++] = getSampleFloat(j, i, n, data); + } + } + } + return pixels; + } + + /** + * Sets all of the samples for a rectangular area of pixels of the + * DataBuffer from a float array. + * + * @param x + * the X coordinate of the rectangle of pixels. + * @param y + * the Y coordinate of the rectangle of pixels. + * @param w + * the width of the rectangle of pixels. + * @param h + * the height of the rectangle of pixels. + * @param fArray + * the float array. + * @param data + * the image data. + */ + public void setPixels(int x, int y, int w, int h, float fArray[], DataBuffer data) { + if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int idx = 0; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numBands; n++) { + setSample(j, i, n, fArray[idx++], data); + } + } + } + } + + /** + * Gets the samples of the specified rectangular area of pixels as a double + * array. + * + * @param x + * the X coordinate of the rectangle of pixels. + * @param y + * the Y coordinate of the rectangle of pixels. + * @param w + * the width of the rectangle of pixels. + * @param h + * the height of the rectangle of pixels. + * @param dArray + * the double array where result will be stored. + * @param data + * the image data. + * @return the double array with the samples of the specified rectangular + * area of pixels. + */ + public double[] getPixels(int x, int y, int w, int h, double dArray[], DataBuffer data) { + if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + double pixels[]; + int idx = 0; + + if (dArray == null) { + pixels = new double[w * h * numBands]; + } else { + pixels = dArray; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numBands; n++) { + pixels[idx++] = getSampleDouble(j, i, n, data); + } + } + } + return pixels; + } + + /** + * Sets all of the samples for a rectangular area of pixels of the + * DataBuffer from a double array. + * + * @param x + * the X coordinate of the rectangle of pixels. + * @param y + * the Y coordinate of the rectangle of pixels. + * @param w + * the width of the rectangle of pixels. + * @param h + * the height of the rectangle of pixels. + * @param dArray + * the double array. + * @param data + * the image data. + */ + public void setPixels(int x, int y, int w, int h, double dArray[], DataBuffer data) { + if (x < 0 || y < 0 || x + w > this.width || y + h > this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int idx = 0; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < numBands; n++) { + setSample(j, i, n, dArray[idx++], data); + } + } + } + } + + /** + * Sets a sample of the specified band for the specified pixel in the + * DataBuffer as integer value. + * + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param b + * the specified band. + * @param s + * the sample as an integer value. + * @param data + * the image data. + */ + public abstract void setSample(int x, int y, int b, int s, DataBuffer data); + + /** + * Gets the samples of a specified band for a specified rectangular area of + * pixels as a integer array. + * + * @param x + * the X coordinate of the rectangle. + * @param y + * the Y coordinate of the rectangle. + * @param w + * the width of the rectangle. + * @param h + * the height of the rectangle. + * @param b + * the specified band. + * @param iArray + * the integer array where result will be stored. + * @param data + * the image data. + * @return the samples of a specified band for a specified rectangular area + * of pixels. + */ + public int[] getSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) { + int samples[]; + int idx = 0; + + if (iArray == null) { + samples = new int[w * h]; + } else { + samples = iArray; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + samples[idx++] = getSample(j, i, b, data); + } + } + + return samples; + } + + /** + * Sets the samples from an integer array in the specified band for the + * specified rectangle of pixels. + * + * @param x + * the X coordinate of the rectangle. + * @param y + * the Y coordinate of the rectangle. + * @param w + * the width of the rectangle. + * @param h + * the height of the rectangle. + * @param b + * the specified band. + * @param iArray + * the integer array. + * @param data + * the image data. + */ + public void setSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) { + int idx = 0; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + setSample(j, i, b, iArray[idx++], data); + } + } + } + + /** + * Gets the samples of a specified band for a specified rectangular area of + * pixels as a float array. + * + * @param x + * the X coordinate of the rectangle. + * @param y + * the Y coordinate of the rectangle. + * @param w + * the width of the rectangle. + * @param h + * the height of the rectangle. + * @param b + * the specified band. + * @param fArray + * the float array where result will be stored. + * @param data + * the image data. + * @return the samples of a specified band for a specified rectangular area + * of pixels. + */ + public float[] getSamples(int x, int y, int w, int h, int b, float fArray[], DataBuffer data) { + float samples[]; + int idx = 0; + + if (fArray == null) { + samples = new float[w * h]; + } else { + samples = fArray; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + samples[idx++] = getSampleFloat(j, i, b, data); + } + } + + return samples; + } + + /** + * Sets the samples from an float array in the specified band for the + * specified rectangle of pixels. + * + * @param x + * the X coordinate of the rectangle. + * @param y + * the Y coordinate of the rectangle. + * @param w + * the width of the rectangle. + * @param h + * the height of the rectangle. + * @param b + * the specified band. + * @param fArray + * the float array. + * @param data + * the image data. + */ + public void setSamples(int x, int y, int w, int h, int b, float fArray[], DataBuffer data) { + int idx = 0; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + setSample(j, i, b, fArray[idx++], data); + } + } + } + + /** + * Gets the samples of a specified band for a specified rectangular area of + * pixels as a double array. + * + * @param x + * the X coordinate of the rectangle. + * @param y + * the Y coordinate of the rectangle. + * @param w + * the width of the rectangle. + * @param h + * the height of the rectangle. + * @param b + * the specified band. + * @param dArray + * the double array where result will be stored. + * @param data + * the image data. + * @return the samples of a specified band for a specified rectangular area + * of pixels. + */ + public double[] getSamples(int x, int y, int w, int h, int b, double dArray[], DataBuffer data) { + double samples[]; + int idx = 0; + + if (dArray == null) { + samples = new double[w * h]; + } else { + samples = dArray; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + samples[idx++] = getSampleDouble(j, i, b, data); + } + } + + return samples; + } + + /** + * Sets the samples from an double array in the specified band for the + * specified rectangle of pixels. + * + * @param x + * the X coordinate of the rectangle. + * @param y + * the Y coordinate of the rectangle. + * @param w + * the width of the rectangle. + * @param h + * the height of the rectangle. + * @param b + * the specified band. + * @param dArray + * the double array. + * @param data + * the image data. + */ + public void setSamples(int x, int y, int w, int h, int b, double dArray[], DataBuffer data) { + int idx = 0; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + setSample(j, i, b, dArray[idx++], data); + } + } + } + + /** + * Sets a sample of the specified band for the specified pixel in the + * DataBuffer as float value. + * + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param b + * the specified band. + * @param s + * the sample as float value. + * @param data + * the image data. + */ + public void setSample(int x, int y, int b, float s, DataBuffer data) { + setSample(x, y, b, (int)s, data); + } + + /** + * Sets a sample of the specified band for the specified pixel in the + * DataBuffer as double value. + * + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param b + * the specified band. + * @param s + * the sample as double value. + * @param data + * the image data. + */ + public void setSample(int x, int y, int b, double s, DataBuffer data) { + setSample(x, y, b, (int)s, data); + } + + /** + * Creates a DataBuffer object which corresponds to the SampleModel. + * + * @return the DataBuffer object which corresponds to the SampleModel. + */ + public abstract DataBuffer createDataBuffer(); + + /** + * Gets the sample size in bits for the specified band. + * + * @param band + * the specified band. + * @return the sample size in bits for the specified band. + */ + public abstract int getSampleSize(int band); + + /** + * Gets an array of the sample size in bits for all bands. + * + * @return an array of the sample size in bits for all bands. + */ + public abstract int[] getSampleSize(); + + /** + * Gets the width of the image data of this SampleModel object. + * + * @return the width of the image data of this SampleModel object. + */ + public final int getWidth() { + return width; + } + + /** + * Gets the transfer type used to transfer pixels via the getDataElements + * and setDataElements methods. Transfer type value can be one of the + * predefined type from DataBuffer class or not. + * + * @return the transfer type. + */ + public int getTransferType() { + return dataType; + } + + /** + * Returns the number of data elements for pixel transferring via the + * getDataElements and setDataElements methods. + * + * @return the number of data elements for pixel transferring via the + * getDataElements and setDataElements methods. + */ + public abstract int getNumDataElements(); + + /** + * Gets the number of bands in the image data of this SampleModel object. + * + * @return the number of bands in the image data of this SampleModel object. + */ + public final int getNumBands() { + return numBands; + } + + /** + * Gets the height of the image data of this SampleModel object. + * + * @return the height of the image data of this SampleModel object. + */ + public final int getHeight() { + return height; + } + + /** + * Gets the data type of image data of this SampleModel object. + * + * @return the data type of image data of this SampleModel object. + */ + public final int getDataType() { + return dataType; + } + +} diff --git a/app/src/main/java/java/awt/image/ShortLookupTable.java b/app/src/main/java/java/awt/image/ShortLookupTable.java new file mode 100644 index 000000000..4319d5805 --- /dev/null +++ b/app/src/main/java/java/awt/image/ShortLookupTable.java @@ -0,0 +1,137 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + * + * @date: Oct 14, 2005 + */ + +package java.awt.image; + +/** + * The ShortLookupTable class provides provides functionality for lookup + * operations, and is defined by an input short array for bands or components of + * image and an offset value. The offset value will be subtracted from the input + * values before indexing the input arrays. The output of a lookup operation is + * represented as an unsigned short array. + * + * @since Android 1.0 + */ +public class ShortLookupTable extends LookupTable { + + /** + * The data. + */ + private short data[][]; + + /** + * Instantiates a new ShortLookupTable with the specified offset value and + * the specified short array which represents lookup table for all bands. + * + * @param offset + * the offset value. + * @param data + * the data array. + */ + public ShortLookupTable(int offset, short[] data) { + super(offset, 1); + this.data = new short[1][data.length]; + // The data array stored as a reference + this.data[0] = data; + } + + /** + * Instantiates a new ShortLookupTable with the specified offset value and + * the specified short array of arrays which represents lookup table for + * each band. + * + * @param offset + * the offset value. + * @param data + * the data array of arrays for each band. + */ + public ShortLookupTable(int offset, short[][] data) { + super(offset, data.length); + this.data = new short[data.length][data[0].length]; + for (int i = 0; i < data.length; i++) { + // The data array for each band stored as a reference + this.data[i] = data[i]; + } + } + + /** + * Gets the lookup table of this ShortLookupTable object. If this + * ShortLookupTable object has one short array for all bands, the returned + * array length is one. + * + * @return the lookup table of this ShortLookupTable object. + */ + public final short[][] getTable() { + return data; + } + + /** + * Returns a short array which contains samples of the specified pixel which + * is translated with the lookup table of this ShortLookupTable object. The + * resulted array is stored to the dst array. + * + * @param src + * the source array. + * @param dst + * the destination array where the result can be stored. + * @return the short array of translated samples of a pixel. + */ + public short[] lookupPixel(short[] src, short[] dst) { + if (dst == null) { + dst = new short[src.length]; + } + + int offset = getOffset(); + if (getNumComponents() == 1) { + for (int i = 0; i < src.length; i++) { + dst[i] = data[0][src[i] - offset]; + } + } else { + for (int i = 0; i < getNumComponents(); i++) { + dst[i] = data[i][src[i] - offset]; + } + } + + return dst; + } + + @Override + public int[] lookupPixel(int[] src, int[] dst) { + if (dst == null) { + dst = new int[src.length]; + } + + int offset = getOffset(); + if (getNumComponents() == 1) { + for (int i = 0; i < src.length; i++) { + dst[i] = data[0][src[i] - offset]; + } + } else { + for (int i = 0; i < getNumComponents(); i++) { + dst[i] = data[i][src[i] - offset]; + } + } + + return dst; + } +} diff --git a/app/src/main/java/java/awt/image/SinglePixelPackedSampleModel.java b/app/src/main/java/java/awt/image/SinglePixelPackedSampleModel.java new file mode 100644 index 000000000..69f3353b3 --- /dev/null +++ b/app/src/main/java/java/awt/image/SinglePixelPackedSampleModel.java @@ -0,0 +1,519 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.util.Arrays; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The SinglePixelPackedSampleModel class represents pixel data where several + * samples combine to create a single pixel and are stored in a single data + * array element. This class supports TYPE_BYTE, TYPE_USHORT, TYPE_INT data + * types. + * + * @since Android 1.0 + */ +public class SinglePixelPackedSampleModel extends SampleModel { + + /** + * The bit masks. + */ + private int bitMasks[]; + + /** + * The bit offsets. + */ + private int bitOffsets[]; + + /** + * The bit sizes. + */ + private int bitSizes[]; + + /** + * The scanline stride. + */ + private int scanlineStride; + + /** + * The max bit size. + */ + private int maxBitSize; + + /** + * Instantiates a new SinglePixelPackedSampleModel with the specified + * parameters. + * + * @param dataType + * the data type of samples. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param bitMasks + * the bit masks for all the bands. + */ + public SinglePixelPackedSampleModel(int dataType, int w, int h, int bitMasks[]) { + this(dataType, w, h, w, bitMasks); + } + + /** + * Instantiates a new SinglePixelPackedSampleModel with the specified + * parameters. + * + * @param dataType + * the data type of the samples. + * @param w + * the width of the image data. + * @param h + * the height of the image data. + * @param scanlineStride + * the scanline stride of the image data. + * @param bitMasks + * the bit masks for all the bands. + */ + public SinglePixelPackedSampleModel(int dataType, int w, int h, int scanlineStride, + int bitMasks[]) { + + super(dataType, w, h, bitMasks.length); + + if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT + && dataType != DataBuffer.TYPE_INT) { + // awt.61=Unsupported data type: {0} + throw new IllegalArgumentException(Messages.getString("awt.61", //$NON-NLS-1$ + dataType)); + } + + this.scanlineStride = scanlineStride; + this.bitMasks = bitMasks.clone(); + this.bitOffsets = new int[this.numBands]; + this.bitSizes = new int[this.numBands]; + + this.maxBitSize = 0; + + for (int i = 0; i < this.numBands; i++) { + int offset = 0; + int size = 0; + int mask = bitMasks[i]; + + if (mask != 0) { + while ((mask & 1) == 0) { + mask >>>= 1; + offset++; + } + + while ((mask & 1) == 1) { + mask >>>= 1; + size++; + } + + if (mask != 0) { + // awt.62=Wrong mask : {0} + throw new IllegalArgumentException(Messages.getString("awt.62", bitMasks[i])); //$NON-NLS-1$ + } + } + + this.bitOffsets[i] = offset; + this.bitSizes[i] = size; + + if (this.maxBitSize < size) { + this.maxBitSize = size; + } + + } + + } + + @Override + public Object getDataElements(int x, int y, Object obj, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + switch (getTransferType()) { + case DataBuffer.TYPE_BYTE: + byte bdata[]; + if (obj == null) { + bdata = new byte[1]; + } else { + bdata = (byte[])obj; + } + + bdata[0] = (byte)data.getElem(y * scanlineStride + x); + obj = bdata; + break; + case DataBuffer.TYPE_USHORT: + short sdata[]; + if (obj == null) { + sdata = new short[1]; + } else { + sdata = (short[])obj; + } + + sdata[0] = (short)data.getElem(y * scanlineStride + x); + obj = sdata; + break; + case DataBuffer.TYPE_INT: + int idata[]; + if (obj == null) { + idata = new int[1]; + } else { + idata = (int[])obj; + } + + idata[0] = data.getElem(y * scanlineStride + x); + obj = idata; + break; + } + return obj; + } + + @Override + public void setDataElements(int x, int y, Object obj, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + switch (getTransferType()) { + case DataBuffer.TYPE_BYTE: + data.setElem(y * scanlineStride + x, ((byte[])obj)[0] & 0xff); + break; + case DataBuffer.TYPE_USHORT: + data.setElem(y * scanlineStride + x, ((short[])obj)[0] & 0xffff); + break; + case DataBuffer.TYPE_INT: + data.setElem(y * scanlineStride + x, ((int[])obj)[0]); + break; + } + } + + /** + * Compares this SinglePixelPackedSampleModel object with the specified + * object. + * + * @param o + * the Object to be compared. + * @return true, if this SinglePixelPackedSampleModel object is equal to the + * specified object, false otherwise. + */ + @Override + public boolean equals(Object o) { + if ((o == null) || !(o instanceof SinglePixelPackedSampleModel)) { + return false; + } + + SinglePixelPackedSampleModel model = (SinglePixelPackedSampleModel)o; + return this.width == model.width && this.height == model.height + && this.numBands == model.numBands && this.dataType == model.dataType + && Arrays.equals(this.bitMasks, model.bitMasks) + && Arrays.equals(this.bitOffsets, model.bitOffsets) + && Arrays.equals(this.bitSizes, model.bitSizes) + && this.scanlineStride == model.scanlineStride; + } + + @Override + public SampleModel createSubsetSampleModel(int bands[]) { + if (bands.length > this.numBands) { + // awt.64=The number of the bands in the subset is greater than the + // number of bands in the sample model + throw new RasterFormatException(Messages.getString("awt.64")); //$NON-NLS-1$ + } + + int masks[] = new int[bands.length]; + for (int i = 0; i < bands.length; i++) { + masks[i] = this.bitMasks[bands[i]]; + } + return new SinglePixelPackedSampleModel(this.dataType, this.width, this.height, + this.scanlineStride, masks); + } + + @Override + public SampleModel createCompatibleSampleModel(int w, int h) { + return new SinglePixelPackedSampleModel(this.dataType, w, h, this.bitMasks); + } + + @Override + public int[] getPixel(int x, int y, int iArray[], DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int pixel[]; + if (iArray == null) { + pixel = new int[this.numBands]; + } else { + pixel = iArray; + } + + for (int i = 0; i < this.numBands; i++) { + pixel[i] = getSample(x, y, i, data); + } + + return pixel; + } + + @Override + public void setPixel(int x, int y, int iArray[], DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + for (int i = 0; i < this.numBands; i++) { + setSample(x, y, i, iArray[i], data); + } + } + + @Override + public int getSample(int x, int y, int b, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int sample = data.getElem(y * scanlineStride + x); + return ((sample & this.bitMasks[b]) >>> this.bitOffsets[b]); + } + + @Override + public int[] getPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) { + if ((x < 0) || (y < 0) || ((long)x + (long)w > this.width) + || ((long)y + (long)h > this.height)) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + int pixels[]; + + if (iArray == null) { + pixels = new int[w * h * this.numBands]; + } else { + pixels = iArray; + } + + int idx = 0; + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < this.numBands; n++) { + pixels[idx++] = getSample(j, i, n, data); + } + } + } + return pixels; + } + + @Override + public void setPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) { + if ((x < 0) || (y < 0) || ((long)x + (long)w > this.width) + || ((long)y + (long)h > this.height)) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + int idx = 0; + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + for (int n = 0; n < this.numBands; n++) { + setSample(j, i, n, iArray[idx++], data); + } + } + } + } + + @Override + public void setSample(int x, int y, int b, int s, DataBuffer data) { + if (x < 0 || y < 0 || x >= this.width || y >= this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + int tmp = data.getElem(y * scanlineStride + x); + tmp &= ~this.bitMasks[b]; + tmp |= (s << this.bitOffsets[b]) & this.bitMasks[b]; + data.setElem(y * scanlineStride + x, tmp); + } + + @Override + public int[] getSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) { + if ((x < 0) || (y < 0) || ((long)x + (long)w > this.width) + || ((long)y + (long)h > this.height)) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + int samples[]; + int idx = 0; + + if (iArray == null) { + samples = new int[w * h]; + } else { + samples = iArray; + } + + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + samples[idx++] = getSample(j, i, b, data); + } + } + + return samples; + } + + @Override + public void setSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) { + if ((x < 0) || (y < 0) || ((long)x + (long)w > this.width) + || ((long)y + (long)h > this.height)) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + int idx = 0; + for (int i = y; i < y + h; i++) { + for (int j = x; j < x + w; j++) { + setSample(x + j, y + i, b, iArray[idx++], data); + } + } + } + + @Override + public DataBuffer createDataBuffer() { + DataBuffer data = null; + int size = (this.height - 1) * scanlineStride + width; + + switch (this.dataType) { + case DataBuffer.TYPE_BYTE: + data = new DataBufferByte(size); + break; + case DataBuffer.TYPE_USHORT: + data = new DataBufferUShort(size); + break; + case DataBuffer.TYPE_INT: + data = new DataBufferInt(size); + break; + } + return data; + } + + /** + * Gets the offset of the specified pixel in the data array. + * + * @param x + * the X coordinate of the specified pixel. + * @param y + * the Y coordinate of the specified pixel. + * @return the offset of the specified pixel. + */ + public int getOffset(int x, int y) { + return (y * scanlineStride + x); + } + + @Override + public int getSampleSize(int band) { + return bitSizes[band]; + } + + @Override + public int[] getSampleSize() { + return bitSizes.clone(); + } + + /** + * Gets an array of the bit offsets of the data array elements. + * + * @return an array of the bit offsets. + */ + public int[] getBitOffsets() { + return bitOffsets.clone(); + } + + /** + * Gets an array of the bit masks for all bands. + * + * @return an array of the bit masks for all bands. + */ + public int[] getBitMasks() { + return bitMasks.clone(); + } + + /** + * Returns a hash code of this MultiPixelPackedSampleModel class. + * + * @return the hash code of this MultiPixelPackedSampleModel class. + */ + @Override + public int hashCode() { + int hash = 0; + int tmp = 0; + + hash = width; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= height; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= numBands; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + hash ^= dataType; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + for (int element : bitMasks) { + hash ^= element; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + } + for (int element : bitOffsets) { + hash ^= element; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + } + for (int element : bitSizes) { + hash ^= element; + tmp = hash >>> 24; + hash <<= 8; + hash |= tmp; + } + hash ^= scanlineStride; + return hash; + } + + /** + * Gets the scanline stride. + * + * @return the scanline stride + */ + public int getScanlineStride() { + return this.scanlineStride; + } + + @Override + public int getNumDataElements() { + return 1; + } + +} diff --git a/app/src/main/java/java/awt/image/TileObserver.java b/app/src/main/java/java/awt/image/TileObserver.java new file mode 100644 index 000000000..7dd97e29b --- /dev/null +++ b/app/src/main/java/java/awt/image/TileObserver.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +/** + * An asynchronous update interface for receiving notifications about tile + * information when tiles of a WritableRenderedImage become modifiable or + * unmodifiable. + * + * @since Android 1.0 + */ +public interface TileObserver { + + /** + * This method is called when information about a tile update is available. + * + * @param source + * the source image. + * @param tileX + * the X index of the tile. + * @param tileY + * the Y index of the tile. + * @param willBeWritable + * parameter which indicates whether the tile will be grabbed for + * writing or be released. + */ + public void tileUpdate(WritableRenderedImage source, int tileX, int tileY, + boolean willBeWritable); + +} diff --git a/app/src/main/java/java/awt/image/VolatileImage.java b/app/src/main/java/java/awt/image/VolatileImage.java new file mode 100644 index 000000000..f24e866bd --- /dev/null +++ b/app/src/main/java/java/awt/image/VolatileImage.java @@ -0,0 +1,146 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey A. Petrenko + * @version $Revision$ + */ + +package java.awt.image; + +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.Image; +import java.awt.ImageCapabilities; +import java.awt.Transparency; + +/** + * The VolatileImage abstract class represents an image which can lose its + * contents at any point. VolatileImage objects are device specific. This class + * provides methods for checking if operation of this image are compatible for + * the GraphicsConfiguration. + * + * @since Android 1.0 + */ +public abstract class VolatileImage extends Image +// Volatile image implements Transparency since 1.5 + implements Transparency { + + /** + * The Constant IMAGE_INCOMPATIBLE indicates that this VolatileImage is not + * applicable for the GraphicsConfiguration object. + */ + public static final int IMAGE_INCOMPATIBLE = 2; + + /** + * The Constant IMAGE_OK indicates that VolatileImage is ready for using. + */ + public static final int IMAGE_OK = 0; + + /** + * The Constant IMAGE_RESTORED indicates that VolatileImage will be ready to + * use after restoring. + */ + public static final int IMAGE_RESTORED = 1; + + /** + * The transparency value of this image. + */ + protected int transparency = OPAQUE; + + /** + * Instantiates a new VolatileImage object. + */ + public VolatileImage() { + super(); + } + + /** + * Returns true if rendering data is lost during validating. This method + * should be called after rendering operation of image. + * + * @return true, if contents lost during validating, false otherwise. + */ + + public abstract boolean contentsLost(); + + /** + * Creates a Graphics2D used to draw in this VolatileImage. + * + * @return the Graphics2D object. + */ + public abstract Graphics2D createGraphics(); + + /** + * Gets the ImageCapabilities of this VolatileImage. + * + * @return the ImageCapabilities of this VolatileImage. + */ + public abstract ImageCapabilities getCapabilities(); + + /** + * Gets the height of this VolatileImage. + * + * @return the height of this VolatileImage. + */ + public abstract int getHeight(); + + /** + * Gets a BufferedImage representation of current VolatileImage that won't + * be affected by any changes to this VolatileImage. + * + * @return a BufferedImage representation of current VolatileImage. + */ + public abstract BufferedImage getSnapshot(); + + /** + * Gets the width of this VolatileImage. + * + * @return the width of this VolatileImage. + */ + public abstract int getWidth(); + + /** + * Validates the drawing surface of the image if the surface had been lost + * and if the specified GraphicsConfiguration object is applicable to this + * image. + * + * @param gc + * the GraphicsConfiguration object. + * @return one of the image status constants: IMAGE_OK, IMAGE_RESTORED or + * IMAGE_INCOMPATIBLE. + */ + public abstract int validate(GraphicsConfiguration gc); + + @Override + public void flush() { + } + + @Override + public Graphics getGraphics() { + return createGraphics(); + } + + @Override + public ImageProducer getSource() { + return getSnapshot().getSource(); + } + + public int getTransparency() { + return transparency; + } +} diff --git a/app/src/main/java/java/awt/image/WritableRaster.java b/app/src/main/java/java/awt/image/WritableRaster.java index a962b73f5..51366ee64 100644 --- a/app/src/main/java/java/awt/image/WritableRaster.java +++ b/app/src/main/java/java/awt/image/WritableRaster.java @@ -1,16 +1,592 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + package java.awt.image; -public class WritableRaster { - private BufferedImage image; +import java.awt.Point; +import java.awt.Rectangle; - public WritableRaster(BufferedImage image) { - this.image = image; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The WritableRaster class provides functionality for writing samples and pixel + * capabilities to the Raster. + * + * @since Android 1.0 + */ +public class WritableRaster extends Raster { + + /** + * Instantiates a new WritableRaster object with the specified SampleModel, + * DataBuffer, rectangular region and parent WritableRaster. + * + * @param sampleModel + * the specified SampleModel. + * @param dataBuffer + * the specified DataBuffer. + * @param aRegion + * the rectangular region which defines the new image bounds. + * @param sampleModelTranslate + * this point defines the translation point from the SampleModel + * to the new WritableRaster coordinates. + * @param parent + * the parent of this WritableRaster. + */ + protected WritableRaster(SampleModel sampleModel, DataBuffer dataBuffer, Rectangle aRegion, + Point sampleModelTranslate, WritableRaster parent) { + super(sampleModel, dataBuffer, aRegion, sampleModelTranslate, parent); } - public DataBuffer getDataBuffer() { - int[] theBuf = new int[(this.image.getWidth() * this.image.getHeight())]; - this.image.getRGB(0, 0, this.image.getWidth(), this.image.getHeight(), theBuf, 0, this.image.getWidth()); - return new DataBufferInt(theBuf, theBuf.length); + /** + * Instantiates a new WritableRaster object with the specified SampleModel + * which defines a layout of this WritableRaster and DataBuffer objects + * which defines the image data. + * + * @param sampleModel + * the specified SampleModel. + * @param dataBuffer + * the specified DataBuffer. + * @param origin + * the point of origin. + */ + protected WritableRaster(SampleModel sampleModel, DataBuffer dataBuffer, Point origin) { + this(sampleModel, dataBuffer, new Rectangle(origin.x, origin.y, sampleModel.width, + sampleModel.height), origin, null); } + + /** + * Instantiates a new WritableRaster with the specified SampleModel. + * + * @param sampleModel + * the specified SampleModel. + * @param origin + * the origin. + */ + protected WritableRaster(SampleModel sampleModel, Point origin) { + this(sampleModel, sampleModel.createDataBuffer(), new Rectangle(origin.x, origin.y, + sampleModel.width, sampleModel.height), origin, null); + } + + /** + * Sets the data for a single pixel from an input Object which represents an + * array of primitive types: DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, + * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or + * DataBuffer.TYPE_DOUBLE. + * + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param inData + * the input data. + */ + public void setDataElements(int x, int y, Object inData) { + sampleModel.setDataElements(x - sampleModelTranslateX, y - sampleModelTranslateY, inData, + dataBuffer); + } + + /** + * Sets the data elements which represent pixel data to the specified + * rectangle area as a primitive array. The following image data types are + * supported: DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, + * DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or + * DataBuffer.TYPE_DOUBLE. + * + * @param x + * the X coordinate of the rectangle of pixels. + * @param y + * the Y coordinate of the rectangle of pixels. + * @param w + * the width of the rectangle of pixels. + * @param h + * the height of the rectangle of pixels. + * @param inData + * the array of primitive type data to be set to the specified + * area. + */ + public void setDataElements(int x, int y, int w, int h, Object inData) { + sampleModel.setDataElements(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, + inData, dataBuffer); + } + + /** + * Creates the child of this WritableRaster by sharing the specified + * rectangular area in this WritableRaster. The parentX, parentY, width and + * height parameters specify rectangular area to be shared. + * + * @param parentX + * the X coordinate of the upper left corner of the shared + * rectangle with respect to this WritableRaster' coordinates. + * @param parentY + * the Y coordinate of the upper left corner of the shared + * rectangle with respect to this WritableRaster' coordinates. + * @param w + * the width of the child area. + * @param h + * the height of the child area. + * @param childMinX + * the X coordinate of child area mapped to the parentX + * coordinate. + * @param childMinY + * the Y coordinate of child area mapped to the parentY + * coordinate. + * @param bandList + * the array of band indices. + * @return the child WritableRaster. + */ + public WritableRaster createWritableChild(int parentX, int parentY, int w, int h, + int childMinX, int childMinY, int bandList[]) { + if (w <= 0 || h <= 0) { + // awt.244=Width or Height of child Raster is less than or equal to + // zero + throw new RasterFormatException(Messages.getString("awt.244")); //$NON-NLS-1$ + } + + if (parentX < this.minX || parentX + w > this.minX + this.width) { + // awt.245=parentX disposes outside Raster + throw new RasterFormatException(Messages.getString("awt.245")); //$NON-NLS-1$ + } + + if (parentY < this.minY || parentY + h > this.minY + this.height) { + // awt.246=parentY disposes outside Raster + throw new RasterFormatException(Messages.getString("awt.246")); //$NON-NLS-1$ + } + + if ((long)parentX + w > Integer.MAX_VALUE) { + // awt.247=parentX + w results in integer overflow + throw new RasterFormatException(Messages.getString("awt.247")); //$NON-NLS-1$ + } + + if ((long)parentY + h > Integer.MAX_VALUE) { + // awt.248=parentY + h results in integer overflow + throw new RasterFormatException(Messages.getString("awt.248")); //$NON-NLS-1$ + } + + if ((long)childMinX + w > Integer.MAX_VALUE) { + // awt.249=childMinX + w results in integer overflow + throw new RasterFormatException(Messages.getString("awt.249")); //$NON-NLS-1$ + } + + if ((long)childMinY + h > Integer.MAX_VALUE) { + // awt.24A=childMinY + h results in integer overflow + throw new RasterFormatException(Messages.getString("awt.24A")); //$NON-NLS-1$ + } + + SampleModel childModel; + + if (bandList == null) { + childModel = sampleModel; + } else { + childModel = sampleModel.createSubsetSampleModel(bandList); + } + + int childTranslateX = childMinX - parentX; + int childTranslateY = childMinY - parentY; + + return new WritableRaster(childModel, dataBuffer, + new Rectangle(childMinX, childMinY, w, h), new Point(childTranslateX + + sampleModelTranslateX, childTranslateY + sampleModelTranslateY), this); + } + + /** + * Creates the translated child of this WritableRaster. New WritableRaster + * object is a reference to the this WritableRaster and with different + * location. + * + * @param childMinX + * the X coordinate of the new WritableRaster. + * @param childMinY + * the Y coordinate of the new WritableRaster. + * @return the WritableRaster. + */ + public WritableRaster createWritableTranslatedChild(int childMinX, int childMinY) { + return createWritableChild(minX, minY, width, height, childMinX, childMinY, null); + } + + /** + * Gets the parent WritableRaster for this WritableRaster object. + * + * @return the parent WritableRaster for this WritableRaster object. + */ + public WritableRaster getWritableParent() { + return (WritableRaster)parent; + } + + /** + * Sets pixels from the specified source Raster srcRaster to this + * WritableRaster. + * + * @param srcRaster + * the source Raster. + */ + public void setRect(Raster srcRaster) { + setRect(0, 0, srcRaster); + } + + /** + * Sets pixels from the specified source Raster srcRaster to this + * WritableRaster. Each pixel with (x, y) coordinates from the source Raster + * is copied to pixel with (x+dx, y+dy) coordinates in this WritableRaster. + * The pixels with (x+dx, y+dy) coordinates which are out the bounds of this + * raster are ignored. + * + * @param dx + * the distance the pixel's X coordinate in the source Raster is + * translated when writtien to this WritableRaster. + * @param dy + * the distance the pixel's Y coordinate in the source Raster is + * translated when writtien to this WritableRaster. + * @param srcRaster + * the source Raster. + */ + public void setRect(int dx, int dy, Raster srcRaster) { + int w = srcRaster.getWidth(); + int h = srcRaster.getHeight(); + + int srcX = srcRaster.getMinX(); + int srcY = srcRaster.getMinY(); + + int dstX = srcX + dx; + int dstY = srcY + dy; + + if (dstX < this.minX) { + int minOffX = this.minX - dstX; + w -= minOffX; + dstX = this.minX; + srcX += minOffX; + } + + if (dstY < this.minY) { + int minOffY = this.minY - dstY; + h -= minOffY; + dstY = this.minY; + srcY += minOffY; + } + + if (dstX + w > this.minX + this.width) { + int maxOffX = (dstX + w) - (this.minX + this.width); + w -= maxOffX; + } + + if (dstY + h > this.minY + this.height) { + int maxOffY = (dstY + h) - (this.minY + this.height); + h -= maxOffY; + } + + if (w <= 0 || h <= 0) { + return; + } + + switch (sampleModel.getDataType()) { + case DataBuffer.TYPE_BYTE: + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: + case DataBuffer.TYPE_INT: + int iPixelsLine[] = null; + for (int i = 0; i < h; i++) { + iPixelsLine = srcRaster.getPixels(srcX, srcY + i, w, 1, iPixelsLine); + setPixels(dstX, dstY + i, w, 1, iPixelsLine); + } + break; + + case DataBuffer.TYPE_FLOAT: + float fPixelsLine[] = null; + for (int i = 0; i < h; i++) { + fPixelsLine = srcRaster.getPixels(srcX, srcY + i, w, 1, fPixelsLine); + setPixels(dstX, dstY + i, w, 1, fPixelsLine); + } + break; + + case DataBuffer.TYPE_DOUBLE: + double dPixelsLine[] = null; + for (int i = 0; i < h; i++) { + dPixelsLine = srcRaster.getPixels(srcX, srcY + i, w, 1, dPixelsLine); + setPixels(dstX, dstY + i, w, 1, dPixelsLine); + } + break; + } + } + + /** + * Sets the data for a rectangle of pixels from an input Raster to this + * WritableRaster. + * + * @param x + * the X coordinate of the point where the data of the input + * Raster is to be written. + * @param y + * the Y coordinate of the point where the data of the input + * Raster is to be written. + * @param inRaster + * the input Raster. + */ + public void setDataElements(int x, int y, Raster inRaster) { + int dstX = x + inRaster.getMinX(); + int dstY = y + inRaster.getMinY(); + + int w = inRaster.getWidth(); + int h = inRaster.getHeight(); + + if (dstX < this.minX || dstX + w > this.minX + this.width || dstY < this.minY + || dstY + h > this.minY + this.height) { + // awt.63=Coordinates are not in bounds + throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ + } + + int srcX = inRaster.getMinX(); + int srcY = inRaster.getMinY(); + Object line = null; + + for (int i = 0; i < h; i++) { + line = inRaster.getDataElements(srcX, srcY + i, w, 1, line); + setDataElements(dstX, dstY + i, w, 1, line); + } + } + + /** + * Sets an integer array of samples for the specified pixel in this + * WritableRaster. + * + * @param x + * the pixel's X coordinate. + * @param y + * the pixel's Y coordinate. + * @param iArray + * the integer array of samples. + */ + public void setPixel(int x, int y, int iArray[]) { + sampleModel.setPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, iArray, + dataBuffer); + } + + /** + * Sets a float array of samples for the specified pixel in this + * WritableRaster. + * + * @param x + * the pixel's X coordinate. + * @param y + * the pixel's Y coordinate. + * @param fArray + * the float array of samples. + */ + public void setPixel(int x, int y, float fArray[]) { + sampleModel.setPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, fArray, + dataBuffer); + } + + /** + * Sets a double array of samples for the specified pixel in this + * WritableRaster. + * + * @param x + * the pixel's X coordinate. + * @param y + * the pixel's Y coordinate. + * @param dArray + * the double array of samples. + */ + public void setPixel(int x, int y, double dArray[]) { + sampleModel.setPixel(x - sampleModelTranslateX, y - sampleModelTranslateY, dArray, + dataBuffer); + } + + /** + * Sets a integer array of samples for the specified rectangular area of + * pixels in this WritableRaster. + * + * @param x + * the X coordinate of rectangular area. + * @param y + * the Y coordinate of rectangular area. + * @param w + * the width of rectangular area. + * @param h + * the height of rectangular area. + * @param iArray + * the integer array of samples. + */ + public void setPixels(int x, int y, int w, int h, int iArray[]) { + sampleModel.setPixels(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, iArray, + dataBuffer); + } + + /** + * Sets a float array of samples for the specified rectangular area of + * pixels in this WritableRaster. + * + * @param x + * the X coordinate of rectangular area. + * @param y + * the Y coordinate of rectangular area. + * @param w + * the width of rectangular area. + * @param h + * the height of rectangular area. + * @param fArray + * the float array of samples. + */ + public void setPixels(int x, int y, int w, int h, float fArray[]) { + sampleModel.setPixels(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, fArray, + dataBuffer); + } + + /** + * Sets a double array of samples for the specified rectangular area of + * pixels in this WritableRaster. + * + * @param x + * the X coordinate of rectangular area. + * @param y + * the Y coordinate of rectangular area. + * @param w + * the width of rectangular area. + * @param h + * the height of rectangular area. + * @param dArray + * the double array of samples. + */ + public void setPixels(int x, int y, int w, int h, double dArray[]) { + sampleModel.setPixels(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, dArray, + dataBuffer); + } + + /** + * Sets the samples for the specified band and the specified rectangular + * area of pixels with an integer array of samples. + * + * @param x + * the X coordinate of the area of pixels. + * @param y + * the Y coordinate of the area of pixels. + * @param w + * the width of the area of pixels. + * @param h + * the height of the area of pixels. + * @param b + * the specified band. + * @param iArray + * the integer array of samples. + */ + public void setSamples(int x, int y, int w, int h, int b, int iArray[]) { + sampleModel.setSamples(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, b, + iArray, dataBuffer); + } + + /** + * Sets the samples for the specified band and the specified rectangular + * area of pixels with a float array of samples. + * + * @param x + * the X coordinate of the area of pixels. + * @param y + * the Y coordinate of the area of pixels. + * @param w + * the width of the area of pixels. + * @param h + * the height of the area of pixels. + * @param b + * the specified band. + * @param fArray + * the float array of samples. + */ + public void setSamples(int x, int y, int w, int h, int b, float fArray[]) { + sampleModel.setSamples(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, b, + fArray, dataBuffer); + } + + /** + * Sets the samples for the specified band and the specified rectangular + * area of pixels with a double array of samples. + * + * @param x + * the X coordinate of the area of pixels. + * @param y + * the Y coordinate of the area of pixels. + * @param w + * the width of the area of pixels. + * @param h + * the height of the area of pixels. + * @param b + * the specified band. + * @param dArray + * the double array of samples. + */ + public void setSamples(int x, int y, int w, int h, int b, double dArray[]) { + sampleModel.setSamples(x - sampleModelTranslateX, y - sampleModelTranslateY, w, h, b, + dArray, dataBuffer); + } + + /** + * Sets the sample for the specified band and the specified pixel with an + * integer sample. + * + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param b + * the specified band. + * @param s + * the sample to be set. + */ + public void setSample(int x, int y, int b, int s) { + sampleModel.setSample(x - sampleModelTranslateX, y - sampleModelTranslateY, b, s, + dataBuffer); + } + + /** + * Sets the sample for the specified band and the specified pixel with a + * float sample. + * + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param b + * the specified band. + * @param s + * the sample to be set. + */ + public void setSample(int x, int y, int b, float s) { + sampleModel.setSample(x - sampleModelTranslateX, y - sampleModelTranslateY, b, s, + dataBuffer); + } + + /** + * Sets the sample for the specified band and the specified pixel with an + * integer sample. + * + * @param x + * the X coordinate of the pixel. + * @param y + * the Y coordinate of the pixel. + * @param b + * the specified band. + * @param s + * the sample to be set. + */ + public void setSample(int x, int y, int b, double s) { + sampleModel.setSample(x - sampleModelTranslateX, y - sampleModelTranslateY, b, s, + dataBuffer); + } + } - diff --git a/app/src/main/java/java/awt/image/WritableRenderedImage.java b/app/src/main/java/java/awt/image/WritableRenderedImage.java new file mode 100644 index 000000000..052353b60 --- /dev/null +++ b/app/src/main/java/java/awt/image/WritableRenderedImage.java @@ -0,0 +1,109 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image; + +import java.awt.Point; + +/** + * The WriteableRenderedImage interface is interface for objects which contains + * Raster data of one or several tiles. This interface provides notification + * mechanism for obtaining tile's writing status. + * + * @since Android 1.0 + */ +public interface WritableRenderedImage extends RenderedImage { + + /** + * Gets and checks out the writable tile for writing. + * + * @param tileX + * the X index of the tile. + * @param tileY + * the Y index of the tile. + * @return the WritableRaster. + */ + public WritableRaster getWritableTile(int tileX, int tileY); + + /** + * Removes the registered TileObserver. + * + * @param to + * the TileObserver which is registered for this + * WritableRenderedImage. + */ + public void removeTileObserver(TileObserver to); + + /** + * Adds the specified TileObserver to this WritableRenderedImage. + * + * @param to + * the TileObserver object to be added. + */ + public void addTileObserver(TileObserver to); + + /** + * Sets this image to the contents of the specified Raster. + * + * @param r + * the specified Raster. + */ + public void setData(Raster r); + + /** + * Gets the array of points which represent indices of tiles which are check + * out for writing. + * + * @return the array of points. + */ + public Point[] getWritableTileIndices(); + + /** + * Checks if the specified tile is writable or not. + * + * @param tileX + * the X index of tile. + * @param tileY + * the Y index of tile. + * @return true, if the specified tile is writable, false otherwise. + */ + public boolean isTileWritable(int tileX, int tileY); + + /** + * Release the specified writable tile. This method removes the writer from + * the tile. + * + * @param tileX + * the X index of the tile. + * @param tileY + * the Y index of the tile. + */ + public void releaseWritableTile(int tileX, int tileY); + + /** + * Checks if there is a tile which is checked out for writing. + * + * @return true, if any tile is checked out for writing, false if there is + * no such tile. + */ + public boolean hasTileWriters(); + +} diff --git a/app/src/main/java/java/awt/image/package.html b/app/src/main/java/java/awt/image/package.html new file mode 100644 index 000000000..b4d6ef0a8 --- /dev/null +++ b/app/src/main/java/java/awt/image/package.html @@ -0,0 +1,8 @@ + + +

+ This package contains classes and interfaces that allow to modify existing images or to create a new image rather than loading it from a file. +

+ @since Android 1.0 + + diff --git a/app/src/main/java/java/awt/image/renderable/ContextualRenderedImageFactory.java b/app/src/main/java/java/awt/image/renderable/ContextualRenderedImageFactory.java new file mode 100644 index 000000000..1881a0c27 --- /dev/null +++ b/app/src/main/java/java/awt/image/renderable/ContextualRenderedImageFactory.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image.renderable; + +import java.awt.geom.Rectangle2D; +import java.awt.image.RenderedImage; + +/** + * A factory for creating ContextualRenderedImage objects with utilities for + * manipulating the properties in the parameter block. + * + * @since Android 1.0 + */ +public interface ContextualRenderedImageFactory extends RenderedImageFactory { + + /** + * Maps a render context to a parameter block and a renderable image. + * + * @param a0 + * the index. + * @param a1 + * the RenderContext. + * @param a2 + * the ParameterBlock. + * @param a3 + * the RenderableImage. + * @return the render context. + */ + public RenderContext mapRenderContext(int a0, RenderContext a1, ParameterBlock a2, + RenderableImage a3); + + /** + * Gets the value of the property from the parameter block. + * + * @param a0 + * the parameter block to examine to find the property. + * @param a1 + * the name of the property. + * @return the value of the property. + */ + public Object getProperty(ParameterBlock a0, String a1); + + /** + * Creates the rendered image determined by the render context and parameter + * block. + * + * @param a0 + * the RenderContext. + * @param a1 + * the ParameterBlock. + * @return the rendered image. + */ + public RenderedImage create(RenderContext a0, ParameterBlock a1); + + /** + * Gets the bounding rectangle from the parameter block. + * + * @param a0 + * the parameter block to read the bounds from. + * @return the bounding rectangle. + */ + public Rectangle2D getBounds2D(ParameterBlock a0); + + /** + * Gets the names of all of the supported properties. + * + * @return the property names. + */ + public String[] getPropertyNames(); + + /** + * Checks if this image factory is dynamic. + * + * @return true, if this image factory is dynamic. + */ + public boolean isDynamic(); + +} diff --git a/app/src/main/java/java/awt/image/renderable/ParameterBlock.java b/app/src/main/java/java/awt/image/renderable/ParameterBlock.java new file mode 100644 index 000000000..7dde73a94 --- /dev/null +++ b/app/src/main/java/java/awt/image/renderable/ParameterBlock.java @@ -0,0 +1,568 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image.renderable; + +import java.awt.image.RenderedImage; +import java.io.Serializable; +import java.util.Vector; + +/** + * The class ParameterBlock groups an indexed set of parameter data with a set + * of renderable (source) images. The mapping between the indexed parameters and + * their property names is provided by a {@link ContextualRenderedImageFactory}. + * + * @since Android 1.0 + */ +public class ParameterBlock implements Cloneable, Serializable { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = -7577115551785240750L; + + /** + * The sources (renderable images). + */ + protected Vector sources = new Vector(); + + /** + * The parameters. + */ + protected Vector parameters = new Vector(); + + /** + * Instantiates a new parameter block. + * + * @param sources + * the vector of source images. + * @param parameters + * the vector of parameters. + */ + public ParameterBlock(Vector sources, Vector parameters) { + setSources(sources); + setParameters(parameters); + } + + /** + * Instantiates a new parameter block with no parameters. + * + * @param sources + * the vector of source images. + */ + public ParameterBlock(Vector sources) { + setSources(sources); + } + + /** + * Instantiates a new parameter block with no image or parameter vectors. + */ + public ParameterBlock() { + } + + /** + * Sets the source image at the specified index. + * + * @param source + * the source image. + * @param index + * the index where the source will be placed. + * @return this parameter block. + */ + public ParameterBlock setSource(Object source, int index) { + if (sources.size() < index + 1) { + sources.setSize(index + 1); + } + sources.setElementAt(source, index); + return this; + } + + /** + * Sets the parameter value object at the specified index. + * + * @param obj + * the parameter value to place at the desired index. + * @param index + * the index where the object is to be placed in the vector of + * parameters. + * @return this parameter block. + */ + public ParameterBlock set(Object obj, int index) { + if (parameters.size() < index + 1) { + parameters.setSize(index + 1); + } + parameters.setElementAt(obj, index); + return this; + } + + /** + * Adds a source to the vector of sources. + * + * @param source + * the source to add. + * @return this parameter block. + */ + public ParameterBlock addSource(Object source) { + sources.addElement(source); + return this; + } + + /** + * Adds the object to the vector of parameter values + * + * @param obj + * the obj to add. + * @return this parameter block. + */ + public ParameterBlock add(Object obj) { + parameters.addElement(obj); + return this; + } + + /** + * Sets the vector of sources, replacing the existing vector of sources, if + * any. + * + * @param sources + * the new sources. + */ + public void setSources(Vector sources) { + this.sources = sources; + } + + /** + * Sets the vector of parameters, replacing the existing vector of + * parameters, if any. + * + * @param parameters + * the new parameters. + */ + public void setParameters(Vector parameters) { + this.parameters = parameters; + } + + /** + * Gets the vector of sources. + * + * @return the sources. + */ + public Vector getSources() { + return sources; + } + + /** + * Gets the vector of parameters. + * + * @return the parameters. + */ + public Vector getParameters() { + return parameters; + } + + /** + * Gets the source at the specified index. + * + * @param index + * the index. + * @return the source object found at the specified index. + */ + public Object getSource(int index) { + return sources.elementAt(index); + } + + /** + * Gets the object parameter found at the specified index. + * + * @param index + * the index. + * @return the parameter object found at the specified index. + */ + public Object getObjectParameter(int index) { + return parameters.elementAt(index); + } + + /** + * Shallow clone (clones using the superclass clone method). + * + * @return the clone of this object. + */ + public Object shallowClone() { + try { + return super.clone(); + } catch (Exception e) { + return null; + } + } + + /** + * Returns a copy of this ParameterBlock instance. + * + * @return the identical copy of this instance. + */ + @SuppressWarnings("unchecked") + @Override + public Object clone() { + ParameterBlock replica; + try { + replica = (ParameterBlock)super.clone(); + } catch (Exception e) { + return null; + } + if (sources != null) { + replica.setSources((Vector)(sources.clone())); + } + if (parameters != null) { + replica.setParameters((Vector)(parameters.clone())); + } + return replica; + } + + /** + * Gets an array of classes corresponding to all of the parameter values + * found in the array of parameters, in order. + * + * @return the parameter classes. + */ + public Class[] getParamClasses() { + int count = parameters.size(); + Class paramClasses[] = new Class[count]; + + for (int i = 0; i < count; i++) { + paramClasses[i] = parameters.elementAt(i).getClass(); + } + return paramClasses; + } + + /** + * Gets the renderable source image found at the specified index in the + * source array. + * + * @param index + * the index. + * @return the renderable source image. + */ + public RenderableImage getRenderableSource(int index) { + return (RenderableImage)sources.elementAt(index); + } + + /** + * Wraps the short value in a Short and places it in the parameter block at + * the specified index. + * + * @param s + * the short value of the parameter. + * @param index + * the index. + * @return this parameter block. + */ + public ParameterBlock set(short s, int index) { + return set(new Short(s), index); + } + + /** + * Wraps the short value in a Short and adds it to the parameter block. + * + * @param s + * the short value of the parameter. + * @return this parameter block. + */ + public ParameterBlock add(short s) { + return add(new Short(s)); + } + + /** + * Wraps the long value in a Long and places it in the parameter block at + * the specified index. + * + * @param l + * the long value of the parameter. + * @param index + * the index. + * @return this parameter block. + */ + public ParameterBlock set(long l, int index) { + return set(new Long(l), index); + } + + /** + * Wraps the long value in a Long and adds it to the parameter block. + * + * @param l + * the long value of the parameter. + * @return this parameter block. + */ + public ParameterBlock add(long l) { + return add(new Long(l)); + } + + /** + * Wraps the integer value in an Integer and places it in the parameter + * block at the specified index. + * + * @param i + * the integer value of the parameter. + * @param index + * the index. + * @return this parameter block. + */ + public ParameterBlock set(int i, int index) { + return set(new Integer(i), index); + } + + /** + * Wraps the integer value in an Integer and adds it to the parameter block. + * + * @param i + * the integer value of the parameter. + * @return this parameter block. + */ + public ParameterBlock add(int i) { + return add(new Integer(i)); + } + + /** + * Wraps the float value in a Float and places it in the parameter block at + * the specified index. + * + * @param f + * the float value of the parameter. + * @param index + * the index. + * @return this parameter block. + */ + public ParameterBlock set(float f, int index) { + return set(new Float(f), index); + } + + /** + * Wraps the float value in a Float and adds it to the parameter block. + * + * @param f + * the float value of the parameter. + * @return this parameter block. + */ + public ParameterBlock add(float f) { + return add(new Float(f)); + } + + /** + * Wraps the double value in a Double and places it in the parameter block + * at the specified index. + * + * @param d + * the double value of the parameter. + * @param index + * the index. + * @return this parameter block. + */ + public ParameterBlock set(double d, int index) { + return set(new Double(d), index); + } + + /** + * Wraps the double value in a Double and adds it to the parameter block. + * + * @param d + * the double value of the parameter. + * @return this parameter block. + */ + public ParameterBlock add(double d) { + return add(new Double(d)); + } + + /** + * Wraps the char value in a Character and places it in the parameter block + * at the specified index. + * + * @param c + * the char value of the parameter. + * @param index + * the index. + * @return this parameter block. + */ + public ParameterBlock set(char c, int index) { + return set(new Character(c), index); + } + + /** + * Wraps the char value in a Character and adds it to the parameter block. + * + * @param c + * the char value of the parameter. + * @return this parameter block. + */ + public ParameterBlock add(char c) { + return add(new Character(c)); + } + + /** + * Wraps the byte value in a Byte and places it in the parameter block at + * the specified index. + * + * @param b + * the byte value of the parameter. + * @param index + * the index. + * @return this parameter block. + */ + public ParameterBlock set(byte b, int index) { + return set(new Byte(b), index); + } + + /** + * Wraps the byte value in a Byte and adds it to the parameter block. + * + * @param b + * the byte value of the parameter. + * @return the parameter block. + */ + public ParameterBlock add(byte b) { + return add(new Byte(b)); + } + + /** + * Gets the RenderedImage at the specified index from the vector of source + * images. + * + * @param index + * the index. + * @return the rendered image. + */ + public RenderedImage getRenderedSource(int index) { + return (RenderedImage)sources.elementAt(index); + } + + /** + * Gets the short-valued parameter found at the desired index in the vector + * of parameter values. + * + * @param index + * the index. + * @return the short parameter. + */ + public short getShortParameter(int index) { + return ((Short)parameters.elementAt(index)).shortValue(); + } + + /** + * Gets the long-valued parameter found at the desired index in the vector + * of parameter values. + * + * @param index + * the index. + * @return the long parameter. + */ + public long getLongParameter(int index) { + return ((Long)parameters.elementAt(index)).longValue(); + } + + /** + * Gets the integer-valued parameter found at the desired index in the + * vector of parameter values. + * + * @param index + * the index. + * @return the integer parameter. + */ + public int getIntParameter(int index) { + return ((Integer)parameters.elementAt(index)).intValue(); + } + + /** + * Gets the float-valued parameter found at the desired index in the vector + * of parameter values. + * + * @param index + * the index. + * @return the float parameter. + */ + public float getFloatParameter(int index) { + return ((Float)parameters.elementAt(index)).floatValue(); + } + + /** + * Gets the double-valued parameter found at the desired index in the vector + * of parameter values. + * + * @param index + * the index. + * @return the double parameter. + */ + public double getDoubleParameter(int index) { + return ((Double)parameters.elementAt(index)).doubleValue(); + } + + /** + * Gets the char-valued parameter found at the desired index in the vector + * of parameter values. + * + * @param index + * the index. + * @return the char parameter. + */ + public char getCharParameter(int index) { + return ((Character)parameters.elementAt(index)).charValue(); + } + + /** + * Gets the byte-valued parameter found at the desired index in the vector + * of parameter values. + * + * @param index + * the index. + * @return the byte parameter. + */ + public byte getByteParameter(int index) { + return ((Byte)parameters.elementAt(index)).byteValue(); + } + + /** + * Clears the vector of sources. + */ + public void removeSources() { + sources.removeAllElements(); + } + + /** + * Clears the vector of parameters. + */ + public void removeParameters() { + parameters.removeAllElements(); + } + + /** + * Gets the number of elements in the vector of sources. + * + * @return the number of elements in the vector of sources. + */ + public int getNumSources() { + return sources.size(); + } + + /** + * Gets the number of elements in the vector of parameters. + * + * @return the number of elements in the vector of parameters. + */ + public int getNumParameters() { + return parameters.size(); + } +} diff --git a/app/src/main/java/java/awt/image/renderable/RenderContext.java b/app/src/main/java/java/awt/image/renderable/RenderContext.java new file mode 100644 index 000000000..0db512faf --- /dev/null +++ b/app/src/main/java/java/awt/image/renderable/RenderContext.java @@ -0,0 +1,214 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image.renderable; + +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.geom.AffineTransform; + +/** + * The Class RenderContext stores data on how an image is to be rendered: the + * affine transform, the area of interest, and the rendering hints. + * + * @since Android 1.0 + */ +public class RenderContext implements Cloneable { + + /** + * The affine transform. + */ + AffineTransform transform; + + /** + * The area of interest. + */ + Shape aoi; + + /** + * The rendering hints. + */ + RenderingHints hints; + + /** + * Instantiates a new render context. + * + * @param usr2dev + * the affine transform. + * @param aoi + * the area of interest. + * @param hints + * the rendering hints. + */ + public RenderContext(AffineTransform usr2dev, Shape aoi, RenderingHints hints) { + this.transform = (AffineTransform)usr2dev.clone(); + this.aoi = aoi; + this.hints = hints; + } + + /** + * Instantiates a new render context with no specified hints. + * + * @param usr2dev + * the affine transform. + * @param aoi + * the area of interest. + */ + public RenderContext(AffineTransform usr2dev, Shape aoi) { + this(usr2dev, aoi, null); + } + + /** + * Instantiates a new render context with no specified area of interest. + * + * @param usr2dev + * the affine transform. + * @param hints + * the rendering hints. + */ + public RenderContext(AffineTransform usr2dev, RenderingHints hints) { + this(usr2dev, null, hints); + } + + /** + * Instantiates a new render context with no rendering hints or area of + * interest. + * + * @param usr2dev + * the affine transform. + */ + public RenderContext(AffineTransform usr2dev) { + this(usr2dev, null, null); + } + + @Override + public Object clone() { + return new RenderContext(transform, aoi, hints); + } + + /** + * Sets the affine transform for this render context. + * + * @param newTransform + * the new affine transform. + */ + public void setTransform(AffineTransform newTransform) { + transform = (AffineTransform)newTransform.clone(); + } + + /** + * Concatenates the current transform with the specified transform (so they + * are applied with the specified transform acting first) and sets the + * resulting transform as the affine transform of this rendering context. + * + * @param modTransform + * the new transform which modifies the current transform. + * @deprecated use + * {@link RenderContext#preConcatenateTransform(AffineTransform)} + * . + */ + @Deprecated + public void preConcetenateTransform(AffineTransform modTransform) { + preConcatenateTransform(modTransform); + } + + /** + * Concatenates the current transform with the specified transform (so they + * are applied with the specified transform acting first) and sets the + * resulting transform as the affine transform of this rendering context. + * + * @param modTransform + * the new transform which modifies the current transform. + */ + public void preConcatenateTransform(AffineTransform modTransform) { + transform.preConcatenate(modTransform); + } + + /** + * Concatenate the specified transform with the current transform. + * + * @param modTransform + * the new transform which modifies the current transform. + * @deprecated use + * {@link RenderContext#concatenateTransform(AffineTransform)}. + */ + @Deprecated + public void concetenateTransform(AffineTransform modTransform) { + concatenateTransform(modTransform); + } + + /** + * Concatenate the specified transform with the current transform. + * + * @param modTransform + * the new transform which modifies the current transform. + */ + public void concatenateTransform(AffineTransform modTransform) { + transform.concatenate(modTransform); + } + + /** + * Gets the transform. + * + * @return the transform. + */ + public AffineTransform getTransform() { + return (AffineTransform)transform.clone(); + } + + /** + * Sets the area of interest. + * + * @param newAoi + * the new area of interest. + */ + public void setAreaOfInterest(Shape newAoi) { + aoi = newAoi; + } + + /** + * Gets the area of interest. + * + * @return the area of interest. + */ + public Shape getAreaOfInterest() { + return aoi; + } + + /** + * Sets the rendering hints. + * + * @param hints + * the new rendering hints. + */ + public void setRenderingHints(RenderingHints hints) { + this.hints = hints; + } + + /** + * Gets the rendering hints. + * + * @return the rendering hints. + */ + public RenderingHints getRenderingHints() { + return hints; + } +} diff --git a/app/src/main/java/java/awt/image/renderable/RenderableImage.java b/app/src/main/java/java/awt/image/renderable/RenderableImage.java new file mode 100644 index 000000000..21332f7d1 --- /dev/null +++ b/app/src/main/java/java/awt/image/renderable/RenderableImage.java @@ -0,0 +1,138 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image.renderable; + +import java.awt.RenderingHints; +import java.awt.image.RenderedImage; +import java.util.Vector; + +/** + * The Interface RenderableImage is implemented by an object that collects all + * of the image-specific data that defines a single image that could be rendered + * to different rendering targets. + * + * @since Android 1.0 + */ +public interface RenderableImage { + + /** + * The Constant HINTS_OBSERVED indicates that the rendering hints are + * applied rather than ignored. + */ + public static final String HINTS_OBSERVED = "HINTS_OBSERVED"; //$NON-NLS-1$ + + /** + * Gets the property from the RenderableImage's parameter block. + * + * @param name + * the name of the property to get. + * @return the value of the property. + */ + public Object getProperty(String name); + + /** + * Creates the rendered image based on the information contained in the + * parameters and the render context. + * + * @param renderContext + * the render context giving rendering specifications such as + * transformations. + * @return the rendered image. + */ + public RenderedImage createRendering(RenderContext renderContext); + + /** + * Creates the scaled rendered image based on the information contained in + * the parameters and the render context. + * + * @param w + * the desired width after scaling or zero if the scaling should + * be proportional, based on the height. + * @param h + * the desired height after scaling or zero if the scaling should + * be proportional, based on the width. + * @param hints + * the rendering hints to use. + * @return the rendered image. + * @throws IllegalArgumentException + * if both the height and width are zero. + */ + public RenderedImage createScaledRendering(int w, int h, RenderingHints hints); + + /** + * Gets the vector of sources from the parameter block. + * + * @return the sources. + */ + public Vector getSources(); + + /** + * Gets the names of all of the supported properties in the current context. + * + * @return the property names. + */ + public String[] getPropertyNames(); + + /** + * Creates the default rendering (using the identity transform and default + * render context). + * + * @return the rendered image. + */ + public RenderedImage createDefaultRendering(); + + /** + * Checks if this context supports dynamic rendering. + * + * @return true, if this context supports dynamic rendering. + */ + public boolean isDynamic(); + + /** + * Gets the width of the image. + * + * @return the width of the image. + */ + public float getWidth(); + + /** + * Gets the y coordinate of the upper left corner. + * + * @return the y coordinate of the upper left corner. + */ + public float getMinY(); + + /** + * Gets the x coordinate of the upper left corner. + * + * @return the x coordinate of the upper left corner. + */ + public float getMinX(); + + /** + * Gets the height of the image. + * + * @return the height of the image. + */ + public float getHeight(); + +} diff --git a/app/src/main/java/java/awt/image/renderable/RenderableImageOp.java b/app/src/main/java/java/awt/image/renderable/RenderableImageOp.java new file mode 100644 index 000000000..dc453727b --- /dev/null +++ b/app/src/main/java/java/awt/image/renderable/RenderableImageOp.java @@ -0,0 +1,191 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image.renderable; + +import java.awt.RenderingHints; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.image.RenderedImage; +import java.util.Vector; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The Class RenderableImageOp is a basic implementation of RenderableImage, + * with methods to access the parameter data and perform rendering operations. + * + * @since Android 1.0 + */ +public class RenderableImageOp implements RenderableImage { + + /** + * The CRIF. + */ + ContextualRenderedImageFactory CRIF; + + /** + * The param block. + */ + ParameterBlock paramBlock; + + /** + * The height. + */ + float minX, minY, width, height; + + /** + * Instantiates a new renderable image op. + * + * @param CRIF + * the cRIF. + * @param paramBlock + * the param block. + */ + public RenderableImageOp(ContextualRenderedImageFactory CRIF, ParameterBlock paramBlock) { + this.CRIF = CRIF; + this.paramBlock = (ParameterBlock)paramBlock.clone(); + Rectangle2D r = CRIF.getBounds2D(paramBlock); + minX = (float)r.getMinX(); + minY = (float)r.getMinY(); + width = (float)r.getWidth(); + height = (float)r.getHeight(); + } + + public Object getProperty(String name) { + return CRIF.getProperty(paramBlock, name); + } + + /** + * Sets the parameter block. + * + * @param paramBlock + * the param block. + * @return the parameter block. + */ + public ParameterBlock setParameterBlock(ParameterBlock paramBlock) { + ParameterBlock oldParam = this.paramBlock; + this.paramBlock = (ParameterBlock)paramBlock.clone(); + return oldParam; + } + + public RenderedImage createRendering(RenderContext renderContext) { + + Vector sources = getSources(); + ParameterBlock rdParam = (ParameterBlock)paramBlock.clone(); + + if (sources != null) { + Vector rdSources = new Vector(); + int i = 0; + while (i < sources.size()) { + RenderContext newContext = CRIF + .mapRenderContext(i, renderContext, paramBlock, this); + RenderedImage rdim = sources.elementAt(i).createRendering(newContext); + + if (rdim != null) { + rdSources.addElement(rdim); + } + i++; + } + if (rdSources.size() > 0) { + rdParam.setSources(rdSources); + } + } + return CRIF.create(renderContext, rdParam); + } + + public RenderedImage createScaledRendering(int w, int h, RenderingHints hints) { + if (w == 0 && h == 0) { + // awt.60=Width and Height mustn't be equal zero both + throw new IllegalArgumentException(Messages.getString("awt.60")); //$NON-NLS-1$ + } + if (w == 0) { + w = Math.round(h * (getWidth() / getHeight())); + } + + if (h == 0) { + h = Math.round(w * (getHeight() / getWidth())); + } + + double sx = (double)w / getWidth(); + double sy = (double)h / getHeight(); + + AffineTransform at = AffineTransform.getScaleInstance(sx, sy); + RenderContext context = new RenderContext(at, hints); + return createRendering(context); + } + + public Vector getSources() { + if (paramBlock.getNumSources() == 0) { + return null; + } + Vector v = new Vector(); + int i = 0; + while (i < paramBlock.getNumSources()) { + Object o = paramBlock.getSource(i); + if (o instanceof RenderableImage) { + v.addElement((RenderableImage)o); + } + i++; + } + return v; + } + + public String[] getPropertyNames() { + return CRIF.getPropertyNames(); + } + + /** + * Gets the parameter block. + * + * @return the parameter block + */ + public ParameterBlock getParameterBlock() { + return paramBlock; + } + + public RenderedImage createDefaultRendering() { + AffineTransform at = new AffineTransform(); + RenderContext context = new RenderContext(at); + return createRendering(context); + } + + public boolean isDynamic() { + return CRIF.isDynamic(); + } + + public float getWidth() { + return width; + } + + public float getMinY() { + return minY; + } + + public float getMinX() { + return minX; + } + + public float getHeight() { + return height; + } + +} diff --git a/app/src/main/java/java/awt/image/renderable/RenderableImageProducer.java b/app/src/main/java/java/awt/image/renderable/RenderableImageProducer.java new file mode 100644 index 000000000..e83ebc76b --- /dev/null +++ b/app/src/main/java/java/awt/image/renderable/RenderableImageProducer.java @@ -0,0 +1,151 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image.renderable; + +import java.awt.image.ColorModel; +import java.awt.image.ImageConsumer; +import java.awt.image.ImageProducer; +import java.awt.image.Raster; +import java.awt.image.RenderedImage; +import java.util.Vector; + +/** + * The Class RenderableImageProducer provides the implementation for the image + * rendering. + * + * @since Android 1.0 + */ +public class RenderableImageProducer implements ImageProducer, Runnable { + + /** + * The rbl. + */ + RenderableImage rbl; + + /** + * The rc. + */ + RenderContext rc; + + /** + * The consumers. + */ + Vector consumers = new Vector(); + + /** + * Instantiates a new renderable image producer. + * + * @param rdblImage + * the rdbl image. + * @param rc + * the rc. + */ + public RenderableImageProducer(RenderableImage rdblImage, RenderContext rc) { + this.rbl = rdblImage; + this.rc = rc; + } + + /** + * Sets the render context. + * + * @param rc + * the new render context. + */ + public synchronized void setRenderContext(RenderContext rc) { + this.rc = rc; + } + + public synchronized boolean isConsumer(ImageConsumer ic) { + return consumers.contains(ic); + } + + public synchronized void startProduction(ImageConsumer ic) { + addConsumer(ic); + Thread t = new Thread(this, "RenderableImageProducer thread"); //$NON-NLS-1$ + t.start(); + } + + public void requestTopDownLeftRightResend(ImageConsumer ic) { + } + + public synchronized void removeConsumer(ImageConsumer ic) { + if (ic != null) { + consumers.removeElement(ic); + } + } + + public synchronized void addConsumer(ImageConsumer ic) { + if (ic != null && !consumers.contains(ic)) { + consumers.addElement(ic); + } + } + + /** + * Creates the rendered image in a new thread. + */ + public void run() { + if (rbl == null) { + return; + } + + RenderedImage rd; + if (rc != null) { + rd = rbl.createRendering(rc); + } else { + rd = rbl.createDefaultRendering(); + } + + ColorModel cm = rd.getColorModel(); + if (cm == null) { + cm = ColorModel.getRGBdefault(); + } + + Raster r = rd.getData(); + int w = r.getWidth(); + int h = r.getHeight(); + + for (ImageConsumer c : consumers) { + c.setDimensions(w, h); + c.setHints(ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES + | ImageConsumer.SINGLEFRAME | ImageConsumer.SINGLEPASS); + } + + int scanLine[] = new int[w]; + int pixel[] = null; + + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + pixel = r.getPixel(x, y, pixel); + scanLine[x] = cm.getDataElement(pixel, 0); + } + + for (ImageConsumer c : consumers) { + c.setPixels(0, y, w, 1, cm, scanLine, 0, w); + } + } + + for (ImageConsumer c : consumers) { + c.imageComplete(ImageConsumer.STATICIMAGEDONE); + } + } + +} diff --git a/app/src/main/java/java/awt/image/renderable/RenderedImageFactory.java b/app/src/main/java/java/awt/image/renderable/RenderedImageFactory.java new file mode 100644 index 000000000..881a40ab7 --- /dev/null +++ b/app/src/main/java/java/awt/image/renderable/RenderedImageFactory.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package java.awt.image.renderable; + +import java.awt.RenderingHints; +import java.awt.image.RenderedImage; + +/** + * A factory for creating RenderedImage objects based on parameters and + * rendering hints. + * + * @since Android 1.0 + */ +public interface RenderedImageFactory { + + /** + * Creates the rendered image. + * + * @param a0 + * the ParameterBlock. + * @param a1 + * the RenderingHints. + * @return the rendered image. + */ + public RenderedImage create(ParameterBlock a0, RenderingHints a1); + +} diff --git a/app/src/main/java/java/awt/image/renderable/package.html b/app/src/main/java/java/awt/image/renderable/package.html new file mode 100644 index 000000000..43aaabc83 --- /dev/null +++ b/app/src/main/java/java/awt/image/renderable/package.html @@ -0,0 +1,8 @@ + + +

+ This package contains classes to create images which are rendering-independent. +

+ @since Android 1.0 + + diff --git a/app/src/main/java/java/awt/mod/ModdingKit.java b/app/src/main/java/java/awt/mod/ModdingKit.java index 8ef5edfd8..55f9b5db1 100644 --- a/app/src/main/java/java/awt/mod/ModdingKit.java +++ b/app/src/main/java/java/awt/mod/ModdingKit.java @@ -1,15 +1,14 @@ package java.awt.mod; +import android.app.*; import android.graphics.*; -import android.util.*; import java.awt.image.*; import java.lang.reflect.*; import java.util.*; -import net.kdt.pojavlaunch.*; public class ModdingKit { - public static MainActivity getCurrentActivity() + public static Activity getCurrentActivity() { try { Class activityThreadClass = Class.forName("android.app.ActivityThread"); @@ -27,7 +26,7 @@ public class ModdingKit if (!pausedField.getBoolean(activityRecord)) { Field activityField = activityRecordClass.getDeclaredField("activity"); activityField.setAccessible(true); - MainActivity activity = (MainActivity) activityField.get(activityRecord); + Activity activity = (Activity) activityField.get(activityRecord); return activity; } } diff --git a/app/src/main/java/java/awt/package.html b/app/src/main/java/java/awt/package.html new file mode 100644 index 000000000..5a6f9f011 --- /dev/null +++ b/app/src/main/java/java/awt/package.html @@ -0,0 +1,8 @@ + + +

+ This package contains classes and interfaces for creating (graphical) user interfaces (GUI), painting 2D graphics and creating, manipulating and drawing images. +

+ @since Android 1.0 + + diff --git a/app/src/main/java/java/awt/peer/ButtonPeer.java b/app/src/main/java/java/awt/peer/ButtonPeer.java new file mode 100644 index 000000000..cc45b4957 --- /dev/null +++ b/app/src/main/java/java/awt/peer/ButtonPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface ButtonPeer { + +} diff --git a/app/src/main/java/java/awt/peer/CanvasPeer.java b/app/src/main/java/java/awt/peer/CanvasPeer.java new file mode 100644 index 000000000..e2763662b --- /dev/null +++ b/app/src/main/java/java/awt/peer/CanvasPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface CanvasPeer { + +} diff --git a/app/src/main/java/java/awt/peer/CheckboxMenuItemPeer.java b/app/src/main/java/java/awt/peer/CheckboxMenuItemPeer.java new file mode 100644 index 000000000..296f42206 --- /dev/null +++ b/app/src/main/java/java/awt/peer/CheckboxMenuItemPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface CheckboxMenuItemPeer { + +} diff --git a/app/src/main/java/java/awt/peer/CheckboxPeer.java b/app/src/main/java/java/awt/peer/CheckboxPeer.java new file mode 100644 index 000000000..e9f8dd192 --- /dev/null +++ b/app/src/main/java/java/awt/peer/CheckboxPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface CheckboxPeer { + +} diff --git a/app/src/main/java/java/awt/peer/ChoicePeer.java b/app/src/main/java/java/awt/peer/ChoicePeer.java new file mode 100644 index 000000000..57b762951 --- /dev/null +++ b/app/src/main/java/java/awt/peer/ChoicePeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface ChoicePeer { + +} diff --git a/app/src/main/java/java/awt/peer/ComponentPeer.java b/app/src/main/java/java/awt/peer/ComponentPeer.java new file mode 100644 index 000000000..bc26791de --- /dev/null +++ b/app/src/main/java/java/awt/peer/ComponentPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface ComponentPeer { + +} diff --git a/app/src/main/java/java/awt/peer/DialogPeer.java b/app/src/main/java/java/awt/peer/DialogPeer.java new file mode 100644 index 000000000..8ae3049bc --- /dev/null +++ b/app/src/main/java/java/awt/peer/DialogPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface DialogPeer { + +} diff --git a/app/src/main/java/java/awt/peer/FileDialogPeer.java b/app/src/main/java/java/awt/peer/FileDialogPeer.java new file mode 100644 index 000000000..0d15e489b --- /dev/null +++ b/app/src/main/java/java/awt/peer/FileDialogPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface FileDialogPeer { + +} diff --git a/app/src/main/java/java/awt/peer/FontPeer.java b/app/src/main/java/java/awt/peer/FontPeer.java index 31a089d7b..fd9815f3e 100644 --- a/app/src/main/java/java/awt/peer/FontPeer.java +++ b/app/src/main/java/java/awt/peer/FontPeer.java @@ -1,39 +1,25 @@ /* - * Copyright (c) 1996, 1998, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. + * http://www.apache.org/licenses/LICENSE-2.0 * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ */ - package java.awt.peer; -/** - * The peer interface for fonts. This is only a marker interface and not - * used by AWT itself. - * - * The peer interfaces are intended only for use in porting - * the AWT. They are not intended for use by application - * developers, and developers should not implement peers - * nor invoke any of the peer methods directly on the peer - * instances. - */ public interface FontPeer { + } diff --git a/app/src/main/java/java/awt/peer/FramePeer.java b/app/src/main/java/java/awt/peer/FramePeer.java new file mode 100644 index 000000000..9cfc40b72 --- /dev/null +++ b/app/src/main/java/java/awt/peer/FramePeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface FramePeer { + +} diff --git a/app/src/main/java/java/awt/peer/LabelPeer.java b/app/src/main/java/java/awt/peer/LabelPeer.java new file mode 100644 index 000000000..052ca9d90 --- /dev/null +++ b/app/src/main/java/java/awt/peer/LabelPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface LabelPeer { + +} diff --git a/app/src/main/java/java/awt/peer/LightweightPeer.java b/app/src/main/java/java/awt/peer/LightweightPeer.java new file mode 100644 index 000000000..1dee90554 --- /dev/null +++ b/app/src/main/java/java/awt/peer/LightweightPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface LightweightPeer { + +} diff --git a/app/src/main/java/java/awt/peer/ListPeer.java b/app/src/main/java/java/awt/peer/ListPeer.java new file mode 100644 index 000000000..0a27885d0 --- /dev/null +++ b/app/src/main/java/java/awt/peer/ListPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface ListPeer { + +} diff --git a/app/src/main/java/java/awt/peer/MenuBarPeer.java b/app/src/main/java/java/awt/peer/MenuBarPeer.java new file mode 100644 index 000000000..3ad2c1603 --- /dev/null +++ b/app/src/main/java/java/awt/peer/MenuBarPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface MenuBarPeer { + +} diff --git a/app/src/main/java/java/awt/peer/MenuComponentPeer.java b/app/src/main/java/java/awt/peer/MenuComponentPeer.java new file mode 100644 index 000000000..3ac3b34a6 --- /dev/null +++ b/app/src/main/java/java/awt/peer/MenuComponentPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface MenuComponentPeer { + +} diff --git a/app/src/main/java/java/awt/peer/MenuItemPeer.java b/app/src/main/java/java/awt/peer/MenuItemPeer.java new file mode 100644 index 000000000..b13389777 --- /dev/null +++ b/app/src/main/java/java/awt/peer/MenuItemPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface MenuItemPeer { + +} diff --git a/app/src/main/java/java/awt/peer/MenuPeer.java b/app/src/main/java/java/awt/peer/MenuPeer.java new file mode 100644 index 000000000..d643ce722 --- /dev/null +++ b/app/src/main/java/java/awt/peer/MenuPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface MenuPeer { + +} diff --git a/app/src/main/java/java/awt/peer/MouseInfoPeer.java b/app/src/main/java/java/awt/peer/MouseInfoPeer.java new file mode 100644 index 000000000..9173a6222 --- /dev/null +++ b/app/src/main/java/java/awt/peer/MouseInfoPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface MouseInfoPeer { + +} diff --git a/app/src/main/java/java/awt/peer/PanelPeer.java b/app/src/main/java/java/awt/peer/PanelPeer.java new file mode 100644 index 000000000..1faa1fe43 --- /dev/null +++ b/app/src/main/java/java/awt/peer/PanelPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface PanelPeer { + +} diff --git a/app/src/main/java/java/awt/peer/PopupMenuPeer.java b/app/src/main/java/java/awt/peer/PopupMenuPeer.java new file mode 100644 index 000000000..cf1ef6111 --- /dev/null +++ b/app/src/main/java/java/awt/peer/PopupMenuPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface PopupMenuPeer { + +} diff --git a/app/src/main/java/java/awt/peer/ScrollPanePeer.java b/app/src/main/java/java/awt/peer/ScrollPanePeer.java new file mode 100644 index 000000000..df3de8383 --- /dev/null +++ b/app/src/main/java/java/awt/peer/ScrollPanePeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface ScrollPanePeer { + +} diff --git a/app/src/main/java/java/awt/peer/ScrollbarPeer.java b/app/src/main/java/java/awt/peer/ScrollbarPeer.java new file mode 100644 index 000000000..eec89611c --- /dev/null +++ b/app/src/main/java/java/awt/peer/ScrollbarPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface ScrollbarPeer { + +} diff --git a/app/src/main/java/java/awt/peer/TextAreaPeer.java b/app/src/main/java/java/awt/peer/TextAreaPeer.java new file mode 100644 index 000000000..636707fd4 --- /dev/null +++ b/app/src/main/java/java/awt/peer/TextAreaPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface TextAreaPeer { + +} diff --git a/app/src/main/java/java/awt/peer/TextFieldPeer.java b/app/src/main/java/java/awt/peer/TextFieldPeer.java new file mode 100644 index 000000000..2b8232a1d --- /dev/null +++ b/app/src/main/java/java/awt/peer/TextFieldPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface TextFieldPeer { + +} diff --git a/app/src/main/java/java/awt/peer/WindowPeer.java b/app/src/main/java/java/awt/peer/WindowPeer.java new file mode 100644 index 000000000..384646f89 --- /dev/null +++ b/app/src/main/java/java/awt/peer/WindowPeer.java @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package java.awt.peer; + +public interface WindowPeer { + +} diff --git a/app/src/main/java/javax/imageio/IIOImage.java b/app/src/main/java/javax/imageio/IIOImage.java new file mode 100644 index 000000000..e9e5130cf --- /dev/null +++ b/app/src/main/java/javax/imageio/IIOImage.java @@ -0,0 +1,224 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.3 $ + */ + +package javax.imageio; + +import javax.imageio.metadata.IIOMetadata; +import java.awt.image.RenderedImage; +import java.awt.image.Raster; +import java.awt.image.BufferedImage; +import java.util.List; + +/** + * The IIOImage class combines the image, image's thumbnail and image's + * metadata. The image can be presented as RenderedImage or Raster object. + * + * @since Android 1.0 + */ +public class IIOImage { + + /** + * The image of this IIOImage. + */ + protected RenderedImage image; + + /** + * The raster of this IIOImage. + */ + protected Raster raster; + + /** + * The list with thumbnails associated with the image. + */ + protected List thumbnails; + + /** + * The metadata associated with the image. + */ + protected IIOMetadata metadata; + + /** + * Instantiates a new IIOImage with the specified RenderedImage, list of + * thumbnails and metadata. + * + * @param image + * the image specified by RenderedImage. + * @param thumbnails + * the list of BufferedImage objects which represent the + * thumbnails of the image. + * @param metadata + * the metadata of the image. + */ + public IIOImage(RenderedImage image, List thumbnails, + IIOMetadata metadata) { + if (image == null) { + throw new IllegalArgumentException("image should not be NULL"); + } + this.raster = null; + this.image = image; + this.thumbnails = thumbnails; + this.metadata = metadata; + } + + /** + * Instantiates a new IIOImage with the specified Raster, list of thumbnails + * and metadata. + * + * @param raster + * the Raster. + * @param thumbnails + * the list of BufferedImage objects which represent the + * thumbnails of Raster data. + * @param metadata + * the metadata. + */ + public IIOImage(Raster raster, List thumbnails, IIOMetadata metadata) { + if (raster == null) { + throw new IllegalArgumentException("raster should not be NULL"); + } + this.image = null; + this.raster = raster; + this.thumbnails = thumbnails; + this.metadata = metadata; + } + + /** + * Gets the RenderedImage object or returns null if this IIOImage object is + * associated with a Raster. + * + * @return the RenderedImage object or null if this IIOImage object is + * associated with a Raster. + */ + public RenderedImage getRenderedImage() { + return image; + } + + /** + * Sets the RenderedImage to this IIOImage object. + * + * @param image + * the RenderedImage to be set to this IIOImage. + */ + public void setRenderedImage(RenderedImage image) { + if (image == null) { + throw new IllegalArgumentException("image should not be NULL"); + } + raster = null; + this.image = image; + } + + /** + * Returns true if the IIOImage object associated with a Raster, or false if + * it's associated with a RenderedImage. + * + * @return true, if the IIOImage object associated with a Raster, or false + * if it's associated with a RenderedImage. + */ + public boolean hasRaster() { + return raster != null; + } + + /** + * Gets the Raster object or returns null if this IIOImage object is + * associated with a RenderedImage. + * + * @return the Raster or null if this IIOImage object is associated with a + * RenderedImage. + */ + public Raster getRaster() { + return raster; + } + + /** + * Sets the Raster to the IIOImage. + * + * @param raster + * the new Raster to the IIOImage. + */ + public void setRaster(Raster raster) { + if (raster == null) { + throw new IllegalArgumentException("raster should not be NULL"); + } + image = null; + this.raster = raster; + } + + /** + * Gets the number of thumbnails for this IIOImage. + * + * @return the number of thumbnails for this IIOImage. + */ + public int getNumThumbnails() { + return thumbnails != null ? thumbnails.size() : 0; + } + + /** + * Gets the thumbnail with the specified index in the list. + * + * @param index + * the index of the thumbnail in the list. + * @return the thumbnail with the specified index in the list. + */ + public BufferedImage getThumbnail(int index) { + if (thumbnails != null) { + return thumbnails.get(index); + } + throw new IndexOutOfBoundsException("no thumbnails were set"); + } + + /** + * Gets the list of thumbnails. + * + * @return the list of thumbnails. + */ + public List getThumbnails() { + return thumbnails; + } + + /** + * Sets the list of thumbnails images to this IIOImage object. + * + * @param thumbnails + * the list of BufferedImage which represent thumbnails. + */ + public void setThumbnails(List thumbnails) { + this.thumbnails = thumbnails; + } + + /** + * Gets the metadata of this IIOImage. + * + * @return the metadata of this IIOImage. + */ + public IIOMetadata getMetadata() { + return metadata; + } + + /** + * Sets the metadata to this IIOImage object. + * + * @param metadata + * the IIOMetadata, or null. + */ + public void setMetadata(IIOMetadata metadata) { + this.metadata = metadata; + } +} diff --git a/app/src/main/java/javax/imageio/IIOParam.java b/app/src/main/java/javax/imageio/IIOParam.java new file mode 100644 index 000000000..2ccc9450f --- /dev/null +++ b/app/src/main/java/javax/imageio/IIOParam.java @@ -0,0 +1,342 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.3 $ + */ + +package javax.imageio; + +import java.awt.*; + +/** + * The IIOParam abstract class is superclass for ImageReadParam and + * ImageWriteParam classes and provides methods and variables which they share. + * + * @since Android 1.0 + */ +public abstract class IIOParam { + + /** + * The source region. + */ + protected Rectangle sourceRegion; + + /** + * The source x subsampling. + */ + protected int sourceXSubsampling = 1; + + /** + * The source y subsampling. + */ + protected int sourceYSubsampling = 1; + + /** + * The subsampling x offset. + */ + protected int subsamplingXOffset; + + /** + * The subsampling y offset. + */ + protected int subsamplingYOffset; + + /** + * The source bands. + */ + protected int[] sourceBands; + + /** + * The destination type. + */ + protected ImageTypeSpecifier destinationType; + + /** + * The destination offset. + */ + protected Point destinationOffset = new Point(0, 0); + + /** + * The default controller. + */ + protected IIOParamController defaultController; + + /** + * The controller. + */ + protected IIOParamController controller; + + /** + * Instantiates a new IIOParam. + */ + protected IIOParam() { + } + + /** + * Sets the source region as a Rectangle object. + * + * @param sourceRegion + * the Rectangle which specifies the source region. + */ + public void setSourceRegion(Rectangle sourceRegion) { + if (sourceRegion != null) { + if (sourceRegion.x < 0) { + throw new IllegalArgumentException("x < 0"); + } + if (sourceRegion.y < 0) { + throw new IllegalArgumentException("y < 0"); + } + if (sourceRegion.width <= 0) { + throw new IllegalArgumentException("width <= 0"); + } + if (sourceRegion.height <= 0) { + throw new IllegalArgumentException("height <= 0"); + } + + if (sourceRegion.width <= subsamplingXOffset) { + throw new IllegalArgumentException("width <= subsamplingXOffset"); + } + + if (sourceRegion.height <= subsamplingYOffset) { + throw new IllegalArgumentException("height <= subsamplingXOffset"); + } + // -- clone it to avoid unexpected modifications + this.sourceRegion = (Rectangle)sourceRegion.clone(); + } else { + this.sourceRegion = null; + } + } + + /** + * Gets the source region. + * + * @return the source region as Rectangle. + */ + public Rectangle getSourceRegion() { + if (sourceRegion == null) { + return null; + } + // -- clone it to avoid unexpected modifications + return (Rectangle)sourceRegion.clone(); + } + + /** + * Sets the source subsampling. The sourceXSubsampling and + * sourceYSubsampling parameters specify the number of rows and columns to + * advance after every source pixel. + * + * @param sourceXSubsampling + * the source X subsampling. + * @param sourceYSubsampling + * the source Y subsampling. + * @param subsamplingXOffset + * the subsampling X offset. + * @param subsamplingYOffset + * the subsampling Y offset. + */ + public void setSourceSubsampling(int sourceXSubsampling, int sourceYSubsampling, + int subsamplingXOffset, int subsamplingYOffset) { + + if (sourceXSubsampling <= 0) { + throw new IllegalArgumentException("sourceXSubsampling <= 0"); + } + if (sourceYSubsampling <= 0) { + throw new IllegalArgumentException("sourceYSubsampling <= 0"); + } + + if (subsamplingXOffset <= 0 || subsamplingXOffset >= sourceXSubsampling) { + throw new IllegalArgumentException("subsamplingXOffset is wrong"); + } + + if (subsamplingYOffset <= 0 || subsamplingYOffset >= sourceYSubsampling) { + throw new IllegalArgumentException("subsamplingYOffset is wrong"); + } + + // -- does region contain pixels + if (sourceRegion != null) { + if (sourceRegion.width <= subsamplingXOffset + || sourceRegion.height <= subsamplingYOffset) { + throw new IllegalArgumentException("there are no pixels in region"); + } + } + + this.sourceXSubsampling = sourceXSubsampling; + this.sourceYSubsampling = sourceYSubsampling; + this.subsamplingXOffset = subsamplingXOffset; + this.subsamplingYOffset = subsamplingYOffset; + } + + /** + * Gets the source X subsampling - the number of source columns to advance + * for each pixel. + * + * @return the source X subsampling. + */ + public int getSourceXSubsampling() { + return sourceXSubsampling; + } + + /** + * Gets the source Y subsampling - the number of source rows to advance for + * each pixel. + * + * @return the source Y subsampling. + */ + public int getSourceYSubsampling() { + return sourceYSubsampling; + } + + /** + * Gets the horizontal offset of the subsampling grid. + * + * @return the horizontal offset of the subsampling grid. + */ + public int getSubsamplingXOffset() { + return subsamplingXOffset; + } + + /** + * Gets the vertical offset of the subsampling grid. + * + * @return the vertical offset of the subsampling grid. + */ + public int getSubsamplingYOffset() { + return subsamplingYOffset; + } + + /** + * Sets the indices of the source bands. + * + * @param sourceBands + * the indices of the source bands. + */ + public void setSourceBands(int[] sourceBands) { + // TODO implement + throw new UnsupportedOperationException("not implemented yet"); + } + + /** + * Gets the array of source bands. + * + * @return the array of source bands. + */ + public int[] getSourceBands() { + // TODO implement + throw new UnsupportedOperationException("not implemented yet"); + } + + /** + * Sets the specified ImageTypeSpecifier for the destination image. + * + * @param destinationType + * the ImageTypeSpecifier. + */ + public void setDestinationType(ImageTypeSpecifier destinationType) { + // TODO implement + throw new UnsupportedOperationException("not implemented yet"); + } + + /** + * Gets the type of the destination image as an ImageTypeSpecifier. . + * + * @return the ImageTypeSpecifier. + */ + public ImageTypeSpecifier getDestinationType() { + // TODO implement + throw new UnsupportedOperationException("not implemented yet"); + } + + /** + * Sets the offset in the destination image where the decoded pixels are + * placed as a result of reading, or specified an area to be written while + * writing operation. + * + * @param destinationOffset + * the destination offset. + */ + public void setDestinationOffset(Point destinationOffset) { + if (destinationOffset == null) { + throw new IllegalArgumentException("destinationOffset == null!"); + } + + this.destinationOffset = (Point)destinationOffset.clone(); + } + + /** + * Gets the offset in the destination image for placing pixels. + * + * @return the offset in the destination image. + */ + public Point getDestinationOffset() { + return (Point)destinationOffset.clone(); + } + + /** + * Sets the IIOParamController to this IIOParam object for providing + * settings to this IIOParam. + * + * @param controller + * the new IIOParamController. + */ + public void setController(IIOParamController controller) { + // TODO implement + throw new UnsupportedOperationException("not implemented yet"); + } + + /** + * Gets the current IIOParamController controller for this IIOParam. + * + * @return the current IIOParamController controller for this IIOParam. + */ + public IIOParamController getController() { + // TODO implement + throw new UnsupportedOperationException("not implemented yet"); + } + + /** + * Gets the default IIOParamController controller for this IIOParam. + * + * @return the default IIOParamController controller for this IIOParam, or + * null. + */ + public IIOParamController getDefaultController() { + // TODO implement + throw new UnsupportedOperationException("not implemented yet"); + } + + /** + * Returns true if IIOParamController is installed for this IIOParam. + * + * @return true, if IIOParamController is installed for this IIOParam, false + * otherwise. + */ + public boolean hasController() { + // TODO implement + throw new UnsupportedOperationException("not implemented yet"); + } + + /** + * Activates the controller. + * + * @return true, if successful, false otherwise. + */ + public boolean activateController() { + // TODO implement + throw new UnsupportedOperationException("not implemented yet"); + } +} diff --git a/app/src/main/java/javax/imageio/IIOParamController.java b/app/src/main/java/javax/imageio/IIOParamController.java new file mode 100644 index 000000000..338cb25a7 --- /dev/null +++ b/app/src/main/java/javax/imageio/IIOParamController.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Sergey I. Salishev + * @version $Revision: 1.2 $ + */ + +package javax.imageio; + +/* + * @author Sergey I. Salishev + * @version $Revision: 1.2 $ + */ + +/** + * The IIOParamController specifies an activate method that invokes the + * controller. + * + * @since Android 1.0 + */ +public interface IIOParamController { + + /** + * Activates the controller. + * + * @param param + * the IIOParam. + * @return true, if the IIOParam has been modified, false otherwise. + */ + boolean activate(IIOParam param); +} diff --git a/app/src/main/java/javax/imageio/ImageIO.java b/app/src/main/java/javax/imageio/ImageIO.java index 17bc610c6..664e1a93d 100644 --- a/app/src/main/java/javax/imageio/ImageIO.java +++ b/app/src/main/java/javax/imageio/ImageIO.java @@ -1,76 +1,817 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.3 $ + */ + package javax.imageio; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; +import javax.imageio.stream.ImageInputStream; +import javax.imageio.stream.ImageOutputStream; +import javax.imageio.spi.*; import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.net.URL; +import java.io.OutputStream; +import java.util.Iterator; +import java.util.Arrays; import java.awt.image.BufferedImage; import java.awt.image.RenderedImage; +import java.net.URL; +import android.graphics.*; +import java.awt.image.*; +import javax.imageio.stream.*; import java.io.*; -import java.awt.mod.*; -import net.kdt.pojavlaunch.*; -public class ImageIO { - public static void setUseCache(boolean set) { - } +/** + * The ImageIO class provides static methods to perform reading and writing + * operations using registered ImageReader and ImageWriter objects. + * + * @since Android 1.0 + */ +public final class ImageIO { - public static BufferedImage read(InputStream is) throws IOException { - return makeBufferedImage(BitmapFactory.decodeStream(is)); - } + /** + * The constant registry. + */ + private static final IIORegistry registry = IIORegistry.getDefaultInstance(); - public static BufferedImage read(File input) throws IOException { - if (!input.exists()) { - throw new FileNotFoundException(input.getAbsolutePath()); - } - System.out.println(input.getAbsolutePath()); - return makeBufferedImage(BitmapFactory.decodeFile(input.getAbsolutePath())); - } - - public static BufferedImage read(URL input) throws IOException { - InputStream is = input.openStream(); - Bitmap bmp = BitmapFactory.decodeStream(is); - is.close(); - return makeBufferedImage(bmp); - } - - private static BufferedImage makeBufferedImage(Bitmap bmp) { - return new BufferedImage(bmp); - } - - public static boolean write(RenderedImage renderedImage, String type, File file) throws IOException { - System.out.println("ImageIO.write stub " + file); - - if (file == null) { - throw new IllegalArgumentException("output cannot be NULL"); - } - if (file.exists()) { - file.delete(); - } - - if (file.getParentFile() == null || !file.getParentFile().exists()) { - file = new File(System.getProperty("user.home", Tools.MAIN_PATH), file.getAbsolutePath()); - } - return write(renderedImage, type, new FileOutputStream(file)); - } + private static boolean isUseCache = false; + private static File cacheDir; - public static boolean write(RenderedImage renderedImage, String type, OutputStream out) throws IOException { - // MOD: Modified to fix blank image result and compatible with Android. - if (renderedImage instanceof BufferedImage) { - try { - Bitmap.CompressFormat format = null; - if (type.equalsIgnoreCase("jpg")) format = Bitmap.CompressFormat.JPEG; - if (type.equalsIgnoreCase("png")) format = Bitmap.CompressFormat.PNG; - // if (str.equalsIgnoreCase("gif")) format = Bitmap.CompressFormat.GIF; - boolean rt = ModdingKit.bufferToBitmap((BufferedImage) renderedImage).compress(format, 100, out); - out.close(); - return rt; - } catch (Exception e) { - e.printStackTrace(); + /** + * Instantiates a new ImageIO. + */ + private ImageIO() { + } + + /** + * Scans for plug-ins in the class path, loads spi classes, and registers + * them with the IIORegistry. + */ + public static void scanForPlugins() { + // throw new UnsupportedOperationException("Not supported yet"); + System.out.println("Warning: Calling an unsupported method javax.imageio.ImageIO.scanForPlugins()"); + } + + /** + * Sets flag which indicates whether a cache file is used when creating + * ImageInputStreams and ImageOutputStreams or not. + * + * @param useCache + * the use cache flag. + */ + public static void setUseCache(boolean useCache) { + isUseCache = useCache; + } + + /** + * Gets the flag which indicates whether a cache file is used when creating + * ImageInputStreams and ImageOutputStreams or not. This method returns the + * current value which is set by setUseCache method. + * + * @return the use cache flag. + */ + public static boolean getUseCache() { + // TODO real implement + return isUseCache; + } + + /** + * Sets the cache directory. + * + * @param cacheDirectory + * the File which specifies a cache directory. + */ + public static void setCacheDirectory(File cacheDirectory) { + cacheDir = cacheDirectory; + } + + /** + * Gets the directory where cache files are created, returned the file which + * is set by setCacheDirectory method, or null. + * + * @return the File object which is set by setCacheDirectory method, or + * null. + */ + public static File getCacheDirectory() { + return cacheDir; + } + + /** + * Creates an ImageInputStream from the specified Object. The specified + * Object should obtain the input source such as File, or InputStream. + * + * @param input + * the input Object such as File, or InputStream. + * @return the ImageInputStream object, or null. + * @throws IOException + * if an I/O exception has occurred. + */ + public static ImageInputStream createImageInputStream(Object input) throws IOException { + + if (input == null) { + throw new IllegalArgumentException("input source cannot be NULL"); + } + + Iterator it = registry.getServiceProviders(ImageInputStreamSpi.class, + true); + + while (it.hasNext()) { + ImageInputStreamSpi spi = it.next(); + if (spi.getInputClass().isInstance(input)) { + return spi.createInputStreamInstance(input); } } + return null; + } + + /** + * Creates an ImageOutputStream using the specified Object. The specified + * Object should obtain the output source such as File, or OutputStream. + * + * @param output + * the output Object such as File, or OutputStream. + * @return the ImageOutputStream object, or null. + * @throws IOException + * if an I/O exception has occurred. + */ + public static ImageOutputStream createImageOutputStream(Object output) throws IOException { + if (output == null) { + throw new IllegalArgumentException("output destination cannot be NULL"); + } + + Iterator it = registry.getServiceProviders( + ImageOutputStreamSpi.class, true); + + while (it.hasNext()) { + ImageOutputStreamSpi spi = it.next(); + if (spi.getOutputClass().isInstance(output)) { + // todo - use getUseCache and getCacheDir here + return spi.createOutputStreamInstance(output); + } + } + return null; + } + + /** + * Gets the array of format names as String which can be decoded by + * registered ImageReader objects. + * + * @return the array of format names. + */ + public static String[] getReaderFormatNames() { + throw new UnsupportedOperationException("Not supported yet"); + } + + /** + * Gets the array of MIME types as String which can be decoded by registered + * ImageReader objects. + * + * @return the array of MIME types. + */ + public static String[] getReaderMIMETypes() { + throw new UnsupportedOperationException("Not supported yet"); + } + + /** + * Gets the Iterator of registered ImageReader which are able to decode an + * input data specified by input Object. + * + * @param input + * the input Object with encoded data such as ImageInputStream + * object. + * @return the Iterator of registered ImageReader. + */ + public static Iterator getImageReaders(Object input) { + if (input == null) { + throw new NullPointerException("input cannot be NULL"); + } + + Iterator it = registry.getServiceProviders(ImageReaderSpi.class, + new CanReadFilter(input), true); + + return new SpiIteratorToReadersIteratorWrapper(it); + } + + /** + * Gets the Iterator of registered ImageReader which are able to decode the + * specified format. + * + * @param formatName + * the format name such as "jpeg", or "gif". + * @return the Iterator of registered ImageReader. + */ + public static Iterator getImageReadersByFormatName(String formatName) { + if (formatName == null) { + throw new NullPointerException("format name cannot be NULL"); + } + + Iterator it = registry.getServiceProviders(ImageReaderSpi.class, + new FormatFilter(formatName), true); + + return new SpiIteratorToReadersIteratorWrapper(it); + } + + /** + * Gets the Iterator which lists the registered ImageReader objects that are + * able to decode files with the specified suffix. + * + * @param fileSuffix + * the file suffix such as "jpg". + * @return the Iterator of registered ImageReaders. + */ + public static Iterator getImageReadersBySuffix(String fileSuffix) { + if (fileSuffix == null) { + throw new NullPointerException("suffix cannot be NULL"); + } + Iterator it = registry.getServiceProviders(ImageReaderSpi.class, + new SuffixFilter(fileSuffix), true); + + return new SpiIteratorToReadersIteratorWrapper(it); + } + + /** + * Gets the Iterator of registered ImageReader objects that are able to + * decode files with the specified MIME type. + * + * @param MIMEType + * the MIME type such as "image/jpeg". + * @return the Iterator of registered ImageReaders. + */ + public static Iterator getImageReadersByMIMEType(String MIMEType) { + throw new UnsupportedOperationException("Not supported yet"); + } + + /** + * Gets an array of Strings giving the names of the formats supported by + * registered ImageWriter objects. + * + * @return the array of format names. + */ + public static String[] getWriterFormatNames() { + throw new UnsupportedOperationException("Not supported yet"); + } + + /** + * Gets an array of Strings giving the MIME types of the formats supported + * by registered ImageWriter objects. + * + * @return the array of MIME types. + */ + public static String[] getWriterMIMETypes() { + throw new UnsupportedOperationException("Not supported yet"); + } + + /** + * Gets the Iterator which lists the registered ImageReader objects that are + * able to encode the specified image format. + * + * @param formatName + * the image format name such as "jpeg". + * @return the Iterator of registered ImageWriter. + */ + public static Iterator getImageWritersByFormatName(String formatName) { + if (formatName == null) { + throw new NullPointerException("format name cannot be NULL"); + } + + Iterator it = registry.getServiceProviders(ImageWriterSpi.class, + new FormatFilter(formatName), true); + + return new SpiIteratorToWritersIteratorWrapper(it); + } + + /** + * Gets the Iterator which lists the registered ImageReader objects that are + * able to encode the specified suffix. + * + * @param fileSuffix + * the file suffix such as "jpg". + * @return the Iterator of registered ImageWriter. + */ + public static Iterator getImageWritersBySuffix(String fileSuffix) { + if (fileSuffix == null) { + throw new NullPointerException("suffix cannot be NULL"); + } + Iterator it = registry.getServiceProviders(ImageWriterSpi.class, + new SuffixFilter(fileSuffix), true); + return new SpiIteratorToWritersIteratorWrapper(it); + } + + /** + * Gets the Iterator which lists the registered ImageReader objects that are + * able to encode the specified MIME type. + * + * @param MIMEType + * the MIME type such as "image/jpeg". + * @return the Iterator of registered ImageWriter. + */ + public static Iterator getImageWritersByMIMEType(String MIMEType) { + throw new UnsupportedOperationException("Not supported yet"); + } + + /** + * Gets an ImageWriter object which corresponds to the specified + * ImageReader, or returns null if the specified ImageReader is not + * registered. + * + * @param reader + * the specified ImageReader. + * @return the ImageWriter, or null. + */ + public static ImageWriter getImageWriter(ImageReader reader) { + throw new UnsupportedOperationException("Not supported yet"); + } + + /** + * Gets an ImageReader object which corresponds to the specified + * ImageWriter, or returns null if the specified ImageWriter is not + * registered. + * + * @param writer + * the registered ImageWriter object. + * @return the ImageReader. + */ + public static ImageReader getImageReader(ImageWriter writer) { + throw new UnsupportedOperationException("Not supported yet"); + } + + /** + * Gets the Iterator of ImageWriter objects which are able to encode images + * with the specified ImageTypeSpecifier and format. + * + * @param type + * the ImageTypeSpecifier, which defines layout. + * @param formatName + * the format name. + * @return the Iterator of ImageWriter objects. + */ + public static Iterator getImageWriters(ImageTypeSpecifier type, String formatName) { + if (type == null) { + throw new NullPointerException("type cannot be NULL"); + } + + if (formatName == null) { + throw new NullPointerException("format name cannot be NULL"); + } + + Iterator it = registry.getServiceProviders(ImageWriterSpi.class, + new FormatAndEncodeFilter(type, formatName), true); + + return new SpiIteratorToWritersIteratorWrapper(it); + } + + /** + * Gets the Iterator of registered ImageTranscoders which are able to + * transcode the metadata of the specified ImageReader object to a suitable + * object for encoding by the specified ImageWriter. + * + * @param reader + * the specified ImageReader. + * @param writer + * the specified ImageWriter. + * @return the Iterator of registered ImageTranscoders. + */ + public static Iterator getImageTranscoders(ImageReader reader, + ImageWriter writer) { + throw new UnsupportedOperationException("Not supported yet"); + } + + /** + * Reads image data from the specified File and decodes it using the + * appropriate registered ImageReader object. The File is wrapped in an + * ImageInputStream. + * + * @param input + * the File to be read. + * @return the BufferedImage decoded from the specified File, or null. + * @throws IOException + * if an I/O exception has occurred. + */ + public static BufferedImage read(File input) throws IOException { + if (input == null) { + throw new IllegalArgumentException("input == null!"); + } + + ImageInputStream stream = createImageInputStream(input); + return read(stream); + } + + /** + * Reads image data from the specified InputStream and decodes it using an + * appropriate registered an ImageReader object. + * + * @param input + * the InputStream. + * @return the BufferedImage decoded from the specified InputStream, or + * null. + * @throws IOException + * if an I/O exception has occurred. + */ + public static BufferedImage read(InputStream input) throws IOException { + if (input == null) { + throw new IllegalArgumentException("input == null!"); + } + + ImageInputStream stream = createImageInputStream(input); + return read(stream); + } + + /** + * Reads image data from the specified URL and decodes it using the + * appropriate registered ImageReader object. + * + * @param input + * the URL to be read. + * @return the BufferedImage decoded from the specified URL, or null. + * @throws IOException + * if an I/O exception has occurred. + */ + public static BufferedImage read(URL input) throws IOException { + if (input == null) { + throw new IllegalArgumentException("input == null!"); + } + + InputStream stream = input.openStream(); + BufferedImage res = read(stream); + stream.close(); + + return res; + } + + /** + * Reads image data from the specified ImageInputStream and decodes it using + * appropriate registered an ImageReader object. + * + * @param stream + * the ImageInputStream. + * @return the BufferedImage decoded from the specified ImageInputStream, or + * null. + * @throws IOException + * if an I/O exception has occurred. + */ + public static BufferedImage read(ImageInputStream stream) throws IOException { + if (stream == null) { + throw new IllegalArgumentException("stream == null!"); + } + + Iterator imageReaders = getImageReaders(stream); + if (!imageReaders.hasNext()) { + return null; + } + + ImageReader reader = imageReaders.next(); + reader.setInput(stream, false, true); + BufferedImage res = reader.read(0); + reader.dispose(); + + try { + stream.close(); + } catch (IOException e) { + // Stream could be already closed, proceed silently in this case + } + + return res; + } + + /** + * Writes the specified image in the specified format (using an appropriate + * ImageWriter) to the specified ImageOutputStream. + * + * @param im + * the RenderedImage. + * @param formatName + * the format name. + * @param output + * the ImageOutputStream where Image to be written. + * @return true, if Image is written successfully, false otherwise. + * @throws IOException + * if an I/O exception has occurred. + */ + public static boolean write(RenderedImage im, String formatName, ImageOutputStream output) + throws IOException { + + if (im == null) { + throw new IllegalArgumentException("image cannot be NULL"); + } + if (formatName == null) { + throw new IllegalArgumentException("format name cannot be NULL"); + } + if (output == null) { + throw new IllegalArgumentException("output cannot be NULL"); + } + + /* + Iterator it = getImageWriters(ImageTypeSpecifier.createFromRenderedImage(im), + formatName); + if (it.hasNext()) { + ImageWriter writer = it.next(); + writer.setOutput(output); + writer.write(im); + output.flush(); + writer.dispose(); + return true; + } + */ + + if (output instanceof FileImageOutputStream && im instanceof BufferedImage) { + int[] pixels = ((BufferedImage) im).getRGB(0, 0, im.getWidth(), im.getHeight(), null, 0, im.getWidth()); + Bitmap androidBitmap = Bitmap.createBitmap(pixels, im.getWidth(), im.getHeight(), Bitmap.Config.ARGB_8888); + FileOutputStream fOutput = new FileOutputStream(((FileImageOutputStream) output).getFile()); + boolean canSave = androidBitmap.compress(Bitmap.CompressFormat.PNG, 100, fOutput); + fOutput.close(); + return canSave; + } return false; } -} + /** + * Writes the specified image in the specified format (using an appropriate + * ImageWriter) to the specified File. + * + * @param im + * the RenderedImage. + * @param formatName + * the format name. + * @param output + * the output File where Image to be written. + * @return true, if Image is written successfully, false otherwise. + * @throws IOException + * if an I/O exception has occurred. + */ + public static boolean write(RenderedImage im, String formatName, File output) + throws IOException { + + if (output == null) { + throw new IllegalArgumentException("output cannot be NULL"); + } + + if (output.exists()) { + output.delete(); + } + + ImageOutputStream ios = createImageOutputStream(output); + boolean rt = write(im, formatName, ios); + ios.close(); + return rt; + } + + /** + * Writes the specified image in the specified format (using an appropriate + * ImageWriter) to the specified OutputStream. + * + * @param im + * the RenderedImage. + * @param formatName + * the format name. + * @param output + * the OutputStream where Image is to be written. + * @return true, if Image is written successfully, false otherwise. + * @throws IOException + * if an I/O exception has occurred. + */ + public static boolean write(RenderedImage im, String formatName, OutputStream output) + throws IOException { + + if (output == null) { + throw new IllegalArgumentException("output cannot be NULL"); + } + + ImageOutputStream ios = createImageOutputStream(output); + boolean rt = write(im, formatName, ios); + ios.close(); + return rt; + } + + /** + * Filter to match spi by format name. + */ + static class FormatFilter implements ServiceRegistry.Filter { + + /** + * The name. + */ + private String name; + + /** + * Instantiates a new format filter. + * + * @param name + * the name. + */ + public FormatFilter(String name) { + this.name = name; + } + + public boolean filter(Object provider) { + ImageReaderWriterSpi spi = (ImageReaderWriterSpi)provider; + return Arrays.asList(spi.getFormatNames()).contains(name); + } + } + + /** + * Filter to match spi by format name and encoding possibility. + */ + static class FormatAndEncodeFilter extends FormatFilter { + + /** + * The type. + */ + private ImageTypeSpecifier type; + + /** + * Instantiates a new format and encode filter. + * + * @param type + * the type. + * @param name + * the name. + */ + public FormatAndEncodeFilter(ImageTypeSpecifier type, String name) { + super(name); + this.type = type; + } + + @Override + public boolean filter(Object provider) { + ImageWriterSpi spi = (ImageWriterSpi)provider; + return super.filter(provider) && spi.canEncodeImage(type); + } + } + + /** + * Filter to match spi by suffix. + */ + static class SuffixFilter implements ServiceRegistry.Filter { + + /** + * The suf. + */ + private String suf; + + /** + * Instantiates a new suffix filter. + * + * @param suf + * the suf. + */ + public SuffixFilter(String suf) { + this.suf = suf; + } + + public boolean filter(Object provider) { + ImageReaderWriterSpi spi = (ImageReaderWriterSpi)provider; + return Arrays.asList(spi.getFileSuffixes()).contains(suf); + } + } + + /** + * Filter to match spi by decoding possibility. + */ + static class CanReadFilter implements ServiceRegistry.Filter { + + /** + * The input. + */ + private Object input; + + /** + * Instantiates a new can read filter. + * + * @param input + * the input. + */ + public CanReadFilter(Object input) { + this.input = input; + } + + public boolean filter(Object provider) { + ImageReaderSpi spi = (ImageReaderSpi)provider; + try { + return spi.canDecodeInput(input); + } catch (IOException e) { + return false; + } + } + } + + /** + * Wraps Spi's iterator to ImageWriter iterator. + */ + static class SpiIteratorToWritersIteratorWrapper implements Iterator { + + /** + * The backend. + */ + private Iterator backend; + + /** + * Instantiates a new spi iterator to writers iterator wrapper. + * + * @param backend + * the backend. + */ + public SpiIteratorToWritersIteratorWrapper(Iterator backend) { + this.backend = backend; + } + + /** + * Next. + * + * @return the image writer. + */ + public ImageWriter next() { + try { + return backend.next().createWriterInstance(); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + /** + * Checks for next. + * + * @return true, if successful. + */ + public boolean hasNext() { + return backend.hasNext(); + } + + /** + * Removes the. + */ + public void remove() { + throw new UnsupportedOperationException( + "Use deregisterServiceprovider instead of Iterator.remove()"); + } + } + + /** + * Wraps spi's iterator to ImageReader iterator. + */ + static class SpiIteratorToReadersIteratorWrapper implements Iterator { + + /** + * The backend. + */ + private Iterator backend; + + /** + * Instantiates a new spi iterator to readers iterator wrapper. + * + * @param backend + * the backend. + */ + public SpiIteratorToReadersIteratorWrapper(Iterator backend) { + this.backend = backend; + } + + /** + * Next. + * + * @return the image reader. + */ + public ImageReader next() { + try { + return backend.next().createReaderInstance(); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + /** + * Checks for next. + * + * @return true, if successful. + */ + public boolean hasNext() { + return backend.hasNext(); + } + + /** + * Removes the. + */ + public void remove() { + throw new UnsupportedOperationException( + "Use deregisterServiceprovider instead of Iterator.remove()"); + } + } +} diff --git a/app/src/main/java/javax/imageio/ImageReadParam.java b/app/src/main/java/javax/imageio/ImageReadParam.java new file mode 100644 index 000000000..9cc5c5f1b --- /dev/null +++ b/app/src/main/java/javax/imageio/ImageReadParam.java @@ -0,0 +1,201 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Sergey I. Salishev + * @version $Revision: 1.2 $ + */ + +package javax.imageio; + +import java.awt.Dimension; +import java.awt.image.BufferedImage; + +/* + * @author Sergey I. Salishev + * @version $Revision: 1.2 $ + */ + +/** + * The ImageReadParam class provides information to the ImageReader about how an + * image is to be decoded. + * + * @since Android 1.0 + */ +public class ImageReadParam extends IIOParam { + + /** + * This flag indicates if this ImageReadParam supports setting the source + * rendering size. + */ + protected boolean canSetSourceRenderSize; + + /** + * The destination BufferedImage. + */ + protected BufferedImage destination; + + /** + * The destination bands. + */ + protected int[] destinationBands; + + /** + * The minimum progressive pass. + */ + protected int minProgressivePass; + + /** + * The number of progressive passes. + */ + protected int numProgressivePasses; + + /** + * The source render size. + */ + protected Dimension sourceRenderSize; + + /** + * Returns true if this ImageReaderParam supports rendering a source image + * at an arbitrary size. + * + * @return true, if this ImageReaderParam supports rendering a source image + * at an arbitrary size, false otherwise. + */ + public boolean canSetSourceRenderSize() { + return canSetSourceRenderSize; + } + + /** + * Gets the current destination image as BufferedImage. + * + * @return the BufferedImage which represents the destination. + */ + public BufferedImage getDestination() { + return destination; + } + + /** + * Gets the indices of destination bands. + * + * @return the array of destination bands. + */ + public int[] getDestinationBands() { + return destinationBands; + } + + /** + * Gets the index of the maximum pass to be decoded. This method returns + * Integer.MAX_VALUE, if getSourceNumProgressivePasses() method returns + * value that is equal to Integer.MAX_VALUE. Otherwise this method returns + * getSourceMinProgressivePass() + getSourceNumProgressivePasses() - 1. + * + * @return the index of the maximum pass to be decoded. + */ + public int getSourceMaxProgressivePass() { + if (getSourceNumProgressivePasses() == Integer.MAX_VALUE) { + return Integer.MAX_VALUE; + } + return getSourceMinProgressivePass() + getSourceNumProgressivePasses() - 1; + } + + /** + * Gets the index of the minimum progressive pass that is decoded, default + * is 0. + * + * @return the index of the minimum progressive pass that is decoded, + * default is 0. + */ + public int getSourceMinProgressivePass() { + return minProgressivePass; + } + + /** + * Gets the number of progressive passes. The default value is + * Integer.MAX_VALUE. + * + * @return the number of progressive passes. + */ + public int getSourceNumProgressivePasses() { + return numProgressivePasses; + } + + /** + * Gets the dimension of source image which will be rendered during decoding + * process. + * + * @return the source render size. + */ + public Dimension getSourceRenderSize() { + return sourceRenderSize; + } + + /** + * Sets the specified destination image. This image will be used by read, + * readAll, and readRaster methods, and a reference to it will be returned + * by those methods. + * + * @param destination + * the destination image. + */ + public void setDestination(BufferedImage destination) { + this.destination = destination; + } + + /** + * Sets the indices of the destination bands. + * + * @param destinationBands + * the indices of the destination bands. + */ + public void setDestinationBands(int[] destinationBands) { + this.destinationBands = destinationBands; + } + + @Override + public void setDestinationType(ImageTypeSpecifier destinationType) { + this.destinationType = destinationType; + } + + /** + * Sets the source progressive passes. + * + * @param minPass + * the index of the minimum pass to be decoded. + * @param numPasses + * the number of passes to be decoded. + */ + public void setSourceProgressivePasses(int minPass, int numPasses) { + minProgressivePass = minPass; + numProgressivePasses = numPasses; + } + + /** + * Sets the dimension size of source image if an image can be rendered at an + * arbitrary size. + * + * @param size + * the size of rendered image. + * @throws UnsupportedOperationException + * the unsupported operation exception. + */ + public void setSourceRenderSize(Dimension size) throws UnsupportedOperationException { + if (!canSetSourceRenderSize) { + throw new UnsupportedOperationException("can't set source renderer size"); + } + sourceRenderSize = size; + } +} diff --git a/app/src/main/java/javax/imageio/ImageReader.java b/app/src/main/java/javax/imageio/ImageReader.java new file mode 100644 index 000000000..cf282ed2a --- /dev/null +++ b/app/src/main/java/javax/imageio/ImageReader.java @@ -0,0 +1,1162 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.3 $ + */ + +package javax.imageio; + +import javax.imageio.spi.ImageReaderSpi; +import javax.imageio.stream.ImageInputStream; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.event.IIOReadWarningListener; +import javax.imageio.event.IIOReadProgressListener; +import javax.imageio.event.IIOReadUpdateListener; +import java.util.Locale; +import java.util.List; +import java.util.Iterator; +import java.util.Set; +import java.io.IOException; +import java.awt.image.BufferedImage; +import java.awt.image.Raster; +import java.awt.image.RenderedImage; +import java.awt.*; + +/** + * The ImageReader class is an abstract class for decoding images. ImageReader + * objects are instantiated by the service provider interface, ImageReaderSpi + * class, for the specific format. ImageReaderSpi class should be registered + * with the IIORegistry, which uses them for format recognition and presentation + * of available format readers and writers. + * + * @since Android 1.0 + */ +public abstract class ImageReader { + + /** + * The originating provider. + */ + protected ImageReaderSpi originatingProvider; + + /** + * The input object such as ImageInputStream. + */ + protected Object input; + + /** + * The seek forward only. + */ + protected boolean seekForwardOnly; + + /** + * The ignore metadata flag indicates whether current input source has been + * marked as metadata is allowed to be ignored by setInput. + */ + protected boolean ignoreMetadata; + + /** + * The minimum index. + */ + protected int minIndex; + + /** + * The available locales. + */ + protected Locale[] availableLocales; + + /** + * The locale. + */ + protected Locale locale; + + /** + * The list of warning listeners. + */ + protected List warningListeners; + + /** + * The list of warning locales. + */ + protected List warningLocales; + + /** + * The list of progress listeners. + */ + protected List progressListeners; + + /** + * The list of update listeners. + */ + protected List updateListeners; + + /** + * Instantiates a new ImageReader. + * + * @param originatingProvider + * the ImageReaderSpi which instantiates this ImageReader. + */ + protected ImageReader(ImageReaderSpi originatingProvider) { + this.originatingProvider = originatingProvider; + } + + /** + * Gets the format name of this input source. + * + * @return the format name of this input source. + * @throws IOException + * if an I/O exception has occurred. + */ + public String getFormatName() throws IOException { + return originatingProvider.getFormatNames()[0]; + } + + /** + * Gets the ImageReaderSpi which instantiated this ImageReader. + * + * @return the ImageReaderSpi. + */ + public ImageReaderSpi getOriginatingProvider() { + return originatingProvider; + } + + /** + * Sets the specified Object as the input source of this ImageReader. + * + * @param input + * the input source, it can be an ImageInputStream or other + * supported objects. + * @param seekForwardOnly + * indicates whether the stream must be read sequentially from + * its current starting point. + * @param ignoreMetadata + * parameter which indicates if metadata may be ignored during + * reads or not. + */ + public void setInput(Object input, boolean seekForwardOnly, boolean ignoreMetadata) { + if (input != null) { + if (!isSupported(input) && !(input instanceof ImageInputStream)) { + throw new IllegalArgumentException("input " + input + " is not supported"); + } + } + this.minIndex = 0; + this.seekForwardOnly = seekForwardOnly; + this.ignoreMetadata = ignoreMetadata; + this.input = input; + } + + /** + * Checks if is supported. + * + * @param input + * the input. + * @return true, if is supported. + */ + private boolean isSupported(Object input) { + ImageReaderSpi spi = getOriginatingProvider(); + if (null != spi) { + Class[] outTypes = spi.getInputTypes(); + for (Class element : outTypes) { + if (element.isInstance(input)) { + return true; + } + } + } + return false; + } + + /** + * Sets the specified Object as the input source of this ImageReader. + * Metadata is not ignored. + * + * @param input + * the input source, it can be an ImageInputStream or other + * supported objects. + * @param seekForwardOnly + * indicates whether the stream must be read sequentially from + * its current starting point. + */ + public void setInput(Object input, boolean seekForwardOnly) { + setInput(input, seekForwardOnly, false); + } + + /** + * Sets the specified Object as the input source of this ImageReader. + * Metadata is not ignored and forward seeking is not required. + * + * @param input + * the input source, it can be ImageInputStream or other objects. + */ + public void setInput(Object input) { + setInput(input, false, false); + } + + /** + * Gets the input source object of this ImageReader, or returns null. + * + * @return the input source object such as ImageInputStream, or null. + */ + public Object getInput() { + return input; + } + + /** + * Checks if the input source supports only forward reading, or not. + * + * @return true, if the input source supports only forward reading, false + * otherwise. + */ + public boolean isSeekForwardOnly() { + return seekForwardOnly; + } + + /** + * Returns true if the current input source allows to metadata to be ignored + * by passing true as the ignoreMetadata argument to the setInput method. + * + * @return true, if the current input source allows to metadata to be + * ignored by passing true as the ignoreMetadata argument to the + * setInput method. + */ + public boolean isIgnoringMetadata() { + return ignoreMetadata; + } + + /** + * Gets the minimum valid index for reading an image, thumbnail, or image + * metadata. + * + * @return the minimum valid index for reading an image, thumbnail, or image + * metadata. + */ + public int getMinIndex() { + return minIndex; + } + + /** + * Gets the available locales. + * + * @return an array of the available locales. + */ + public Locale[] getAvailableLocales() { + return availableLocales; + } + + /** + * Sets the locale to this ImageReader. + * + * @param locale + * the Locale. + */ + public void setLocale(Locale locale) { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Gets the locale of this ImageReader. + * + * @return the locale of this ImageReader. + */ + public Locale getLocale() { + return locale; + } + + /** + * Gets the number of images available in the current input source. + * + * @param allowSearch + * the parameter which indicates what a search is required; if + * false, the reader may return -1 without searching. + * @return the number of images. + * @throws IOException + * if an I/O exception has occurred. + */ + public abstract int getNumImages(boolean allowSearch) throws IOException; + + /** + * Gets the width of the specified image in input source. + * + * @param imageIndex + * the image index. + * @return the width in pixels. + * @throws IOException + * if an I/O exception has occurred. + */ + public abstract int getWidth(int imageIndex) throws IOException; + + /** + * Gets the height of the specified image in input source. + * + * @param imageIndex + * the image index. + * @return the height in pixels. + * @throws IOException + * if an I/O exception has occurred. + */ + public abstract int getHeight(int imageIndex) throws IOException; + + /** + * Checks if the storage format of the specified image places an impediment + * on random pixels access or not. + * + * @param imageIndex + * the image's index. + * @return true, if the storage format of the specified image places an + * impediment on random pixels access, false otherwise. + * @throws IOException + * if an I/O exception has occurred. + */ + public boolean isRandomAccessEasy(int imageIndex) throws IOException { + return false; // def + } + + /** + * Gets the aspect ratio (width devided by height) of the image. + * + * @param imageIndex + * the image index. + * @return the aspect ratio of the image. + * @throws IOException + * if an I/O exception has occurred. + */ + public float getAspectRatio(int imageIndex) throws IOException { + return (float)getWidth(imageIndex) / getHeight(imageIndex); + } + + /** + * Gets an ImageTypeSpecifier which indicates the type of the specified + * image. + * + * @param imageIndex + * the image's index. + * @return the ImageTypeSpecifier. + * @throws IOException + * if an I/O exception has occurred. + */ + public ImageTypeSpecifier getRawImageType(int imageIndex) throws IOException { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Gets an Iterator of ImageTypeSpecifier objects which are associated with + * image types that may be used when decoding specified image. + * + * @param imageIndex + * the image index. + * @return an Iterator of ImageTypeSpecifier objects. + * @throws IOException + * if an I/O exception has occurred. + */ + public abstract Iterator getImageTypes(int imageIndex) throws IOException; + + /** + * Gets the default ImageReadParam object. + * + * @return the ImageReadParam object. + */ + public ImageReadParam getDefaultReadParam() { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Gets an IIOMetadata object for this input source. + * + * @return the IIOMetadata. + * @throws IOException + * if an I/O exception has occurred. + */ + public abstract IIOMetadata getStreamMetadata() throws IOException; + + /** + * Gets an IIOMetadata object for this input source. + * + * @param formatName + * the desired metadata format to be used in the returned + * IIOMetadata object. + * @param nodeNames + * the node names of the document. + * @return the IIOMetadata. + * @throws IOException + * if an I/O exception has occurred. + */ + public IIOMetadata getStreamMetadata(String formatName, Set nodeNames) + throws IOException { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Gets the image metadata of the specified image in input source. + * + * @param imageIndex + * the image index. + * @return the IIOMetadata. + * @throws IOException + * if an I/O exception has occurred. + */ + public abstract IIOMetadata getImageMetadata(int imageIndex) throws IOException; + + /** + * Gets the image metadata of the specified image input source. + * + * @param imageIndex + * the image index. + * @param formatName + * the desired metadata format to be used in the returned + * IIOMetadata object. + * @param nodeNames + * the node names which can be contained in the document. + * @return the IIOMetadata. + * @throws IOException + * if an I/O exception has occurred. + */ + public IIOMetadata getImageMetadata(int imageIndex, String formatName, Set nodeNames) + throws IOException { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Reads the specified image and returns it as a BufferedImage using the + * default ImageReadParam. + * + * @param imageIndex + * the image index. + * @return the BufferedImage. + * @throws IOException + * if an I/O exception has occurred. + */ + public BufferedImage read(int imageIndex) throws IOException { + return read(imageIndex, null); + } + + /** + * Reads the specified image and returns it as a BufferedImage using the + * specified ImageReadParam. + * + * @param imageIndex + * the image index. + * @param param + * the ImageReadParam. + * @return the BufferedImage. + * @throws IOException + * if an I/O exception has occurred. + */ + public abstract BufferedImage read(int imageIndex, ImageReadParam param) throws IOException; + + /** + * Reads the specified image and returns an IIOImage with this image, + * thumbnails, and metadata for this image, using the specified + * ImageReadParam. + * + * @param imageIndex + * the image index. + * @param param + * the ImageReadParam. + * @return the IIOImage. + * @throws IOException + * if an I/O exception has occurred. + */ + public IIOImage readAll(int imageIndex, ImageReadParam param) throws IOException { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Returns an Iterator of IIOImages from the input source. + * + * @param params + * the Iterator of ImageReadParam objects. + * @return the iterator of IIOImages. + * @throws IOException + * if an I/O exception has occurred. + */ + public Iterator readAll(Iterator params) throws IOException { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Checks whether or not this plug-in supports reading a Raster. + * + * @return true, if this plug-in supports reading a Raster, false otherwise. + */ + public boolean canReadRaster() { + return false; // def + } + + /** + * Reads a new Raster object which contains the raw pixel data from the + * image. + * + * @param imageIndex + * the image index. + * @param param + * the ImageReadParam. + * @return the Raster. + * @throws IOException + * if an I/O exception has occurred. + */ + public Raster readRaster(int imageIndex, ImageReadParam param) throws IOException { + throw new UnsupportedOperationException("Unsupported"); + } + + /** + * Checks if the specified image has tiles or not. + * + * @param imageIndex + * the image's index. + * @return true, if the specified image has tiles, false otherwise. + * @throws IOException + * if an I/O exception has occurred. + */ + public boolean isImageTiled(int imageIndex) throws IOException { + return false; // def + } + + /** + * Gets the tile width in the specified image. + * + * @param imageIndex + * the image's index. + * @return the tile width. + * @throws IOException + * if an I/O exception has occurred. + */ + public int getTileWidth(int imageIndex) throws IOException { + return getWidth(imageIndex); // def + } + + /** + * Gets the tile height in the specified image. + * + * @param imageIndex + * the image's index. + * @return the tile height. + * @throws IOException + * if an I/O exception has occurred. + */ + public int getTileHeight(int imageIndex) throws IOException { + return getHeight(imageIndex); // def + } + + /** + * Gets the X coordinate of the upper left corner of the tile grid in the + * specified image. + * + * @param imageIndex + * the image's index. + * @return the X coordinate of the upper left corner of the tile grid. + * @throws IOException + * if an I/O exception has occurred. + */ + public int getTileGridXOffset(int imageIndex) throws IOException { + return 0; // def + } + + /** + * Gets the Y coordinate of the upper left corner of the tile grid in the + * specified image. + * + * @param imageIndex + * the image's index. + * @return the Y coordinate of the upper left corner of the tile grid. + * @throws IOException + * if an I/O exception has occurred. + */ + public int getTileGridYOffset(int imageIndex) throws IOException { + return 0; // def + } + + /** + * Reads the tile specified by the tileX and tileY parameters of the + * specified image and returns it as a BufferedImage. + * + * @param imageIndex + * the image index. + * @param tileX + * the X index of tile. + * @param tileY + * the Y index of tile. + * @return the BufferedImage. + * @throws IOException + * if an I/O exception has occurred. + */ + public BufferedImage readTile(int imageIndex, int tileX, int tileY) throws IOException { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Reads the tile specified by the tileX and tileY parameters of the + * specified image and returns it as a Raster. + * + * @param imageIndex + * the image index. + * @param tileX + * the X index of tile. + * @param tileY + * the Y index of tile. + * @return the Raster. + * @throws IOException + * if an I/O exception has occurred. + */ + public Raster readTileRaster(int imageIndex, int tileX, int tileY) throws IOException { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Reads the specified image using the specified ImageReadParam and returns + * it as a RenderedImage. + * + * @param imageIndex + * the image index. + * @param param + * the ImageReadParam. + * @return the RenderedImage. + * @throws IOException + * if an I/O exception has occurred. + */ + public RenderedImage readAsRenderedImage(int imageIndex, ImageReadParam param) + throws IOException { + return read(imageIndex, param); + } + + /** + * Returns true if the image format supported by this reader supports + * thumbnail preview images. + * + * @return true, if the image format supported by this reader supports + * thumbnail preview images, false otherwise. + */ + public boolean readerSupportsThumbnails() { + return false; // def + } + + /** + * Checks if the specified image has thumbnails or not. + * + * @param imageIndex + * the image's index. + * @return true, if the specified image has thumbnails, false otherwise. + * @throws IOException + * if an I/O exception has occurred. + */ + public boolean hasThumbnails(int imageIndex) throws IOException { + return getNumThumbnails(imageIndex) > 0; // def + } + + /** + * Gets the number of thumbnails for the specified image. + * + * @param imageIndex + * the image's index. + * @return the number of thumbnails. + * @throws IOException + * if an I/O exception has occurred. + */ + public int getNumThumbnails(int imageIndex) throws IOException { + return 0; // def + } + + /** + * Gets the width of the specified thumbnail for the specified image. + * + * @param imageIndex + * the image's index. + * @param thumbnailIndex + * the thumbnail's index. + * @return the thumbnail width. + * @throws IOException + * if an I/O exception has occurred. + */ + public int getThumbnailWidth(int imageIndex, int thumbnailIndex) throws IOException { + return readThumbnail(imageIndex, thumbnailIndex).getWidth(); // def + } + + /** + * Gets the height of the specified thumbnail for the specified image. + * + * @param imageIndex + * the image's index. + * @param thumbnailIndex + * the thumbnail's index. + * @return the thumbnail height. + * @throws IOException + * if an I/O exception has occurred. + */ + public int getThumbnailHeight(int imageIndex, int thumbnailIndex) throws IOException { + return readThumbnail(imageIndex, thumbnailIndex).getHeight(); // def + } + + /** + * Reads the thumbnail image for the specified image as a BufferedImage. + * + * @param imageIndex + * the image index. + * @param thumbnailIndex + * the thumbnail index. + * @return the BufferedImage. + * @throws IOException + * if an I/O exception has occurred. + */ + public BufferedImage readThumbnail(int imageIndex, int thumbnailIndex) throws IOException { + throw new UnsupportedOperationException("Unsupported"); // def + } + + /** + * Requests an abort operation for current reading operation. + */ + public void abort() { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Checks whether or not a request to abort the current read operation has + * been made successfully. + * + * @return true, if the request to abort the current read operation has been + * made successfully, false otherwise. + */ + protected boolean abortRequested() { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Clears all previous abort request, and abortRequested returns false after + * calling this method. + */ + protected void clearAbortRequest() { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Adds the IIOReadWarningListener. + * + * @param listener + * the IIOReadWarningListener. + */ + public void addIIOReadWarningListener(IIOReadWarningListener listener) { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Removes the specified IIOReadWarningListener. + * + * @param listener + * the IIOReadWarningListener to be removed. + */ + public void removeIIOReadWarningListener(IIOReadWarningListener listener) { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Removes all registered IIOReadWarningListeners. + */ + public void removeAllIIOReadWarningListeners() { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Adds the IIOReadProgressListener. + * + * @param listener + * the IIOReadProgressListener. + */ + public void addIIOReadProgressListener(IIOReadProgressListener listener) { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Removes the specified IIOReadProgressListener. + * + * @param listener + * the IIOReadProgressListener to be removed. + */ + public void removeIIOReadProgressListener(IIOReadProgressListener listener) { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Removes registered IIOReadProgressListeners. + */ + public void removeAllIIOReadProgressListeners() { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Adds the IIOReadUpdateListener. + * + * @param listener + * the IIOReadUpdateListener. + */ + public void addIIOReadUpdateListener(IIOReadUpdateListener listener) { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Removes the specified IIOReadUpdateListener. + * + * @param listener + * the IIOReadUpdateListener to be removed. + */ + public void removeIIOReadUpdateListener(IIOReadUpdateListener listener) { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Removes registered IIOReadUpdateListeners. + */ + public void removeAllIIOReadUpdateListeners() { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Processes the start of an sequence of image reads by calling the + * sequenceStarted method on all registered IIOReadProgressListeners. + * + * @param minIndex + * the minimum index. + */ + protected void processSequenceStarted(int minIndex) { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Processes the completion of an sequence of image reads by calling + * sequenceComplete method on all registered IIOReadProgressListeners. + */ + protected void processSequenceComplete() { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Processes the start of an image read by calling the imageStarted method + * on all registered IIOReadProgressListeners. + * + * @param imageIndex + * the image index. + */ + protected void processImageStarted(int imageIndex) { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Processes the current percentage of image completion by calling the + * imageProgress method on all registered IIOReadProgressListeners. + * + * @param percentageDone + * the percentage done. + */ + protected void processImageProgress(float percentageDone) { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Processes image completion by calling the imageComplete method on all + * registered IIOReadProgressListeners. + */ + protected void processImageComplete() { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Processes the start of a thumbnail read by calling the thumbnailStarted + * method on all registered IIOReadProgressListeners. + * + * @param imageIndex + * the image index. + * @param thumbnailIndex + * the thumbnail index. + */ + protected void processThumbnailStarted(int imageIndex, int thumbnailIndex) { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Processes the current percentage of thumbnail completion by calling the + * thumbnailProgress method on all registered IIOReadProgressListeners. + * + * @param percentageDone + * the percentage done. + */ + protected void processThumbnailProgress(float percentageDone) { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Processes the completion of a thumbnail read by calling the + * thumbnailComplete method on all registered IIOReadProgressListeners. + */ + protected void processThumbnailComplete() { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Processes a read aborted event by calling the readAborted method on all + * registered IIOReadProgressListeners. + */ + protected void processReadAborted() { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Processes the beginning of a progressive pass by calling the passStarted + * method on all registered IIOReadUpdateListeners. + * + * @param theImage + * the image to be updated. + * @param pass + * the current pass index. + * @param minPass + * the minimum pass index. + * @param maxPass + * the maximum pass index. + * @param minX + * the X coordinate of of the upper left pixel. + * @param minY + * the Y coordinate of of the upper left pixel. + * @param periodX + * the horizontal separation between pixels. + * @param periodY + * the vertical separation between pixels. + * @param bands + * the number of affected bands. + */ + protected void processPassStarted(BufferedImage theImage, int pass, int minPass, int maxPass, + int minX, int minY, int periodX, int periodY, int[] bands) { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Processes the update of a set of samples by calling the imageUpdate + * method on all registered IIOReadUpdateListeners. + * + * @param theImage + * the image to be updated. + * @param minX + * the X coordinate of the upper left pixel. + * @param minY + * the Y coordinate of the upper left pixel. + * @param width + * the width of updated area. + * @param height + * the height of updated area. + * @param periodX + * the horizontal separation between pixels. + * @param periodY + * the vertical separation between pixels. + * @param bands + * the number of affected bands. + */ + protected void processImageUpdate(BufferedImage theImage, int minX, int minY, int width, + int height, int periodX, int periodY, int[] bands) { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Processes the end of a progressive pass by calling passComplete method of + * registered IIOReadUpdateListeners. + * + * @param theImage + * the image to be updated. + */ + protected void processPassComplete(BufferedImage theImage) { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Processes the beginning of a thumbnail progressive pass by calling the + * thumbnailPassStarted method on all registered IIOReadUpdateListeners. + * + * @param theThumbnail + * the thumbnail to be updated. + * @param pass + * the current pass index. + * @param minPass + * the minimum pass index. + * @param maxPass + * the maximum pass index. + * @param minX + * the X coordinate of the upper left pixel. + * @param minY + * the Y coordinate of the upper left pixel. + * @param periodX + * the horizontal separation between pixels. + * @param periodY + * the vertical separation between pixels. + * @param bands + * the number of affected bands. + */ + protected void processThumbnailPassStarted(BufferedImage theThumbnail, int pass, int minPass, + int maxPass, int minX, int minY, int periodX, int periodY, int[] bands) { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Processes the update of a set of samples in a thumbnail image by calling + * the thumbnailUpdate method on all registered IIOReadUpdateListeners. + * + * @param theThumbnail + * the thumbnail to be updated. + * @param minX + * the X coordinate of the upper left pixel. + * @param minY + * the Y coordinate of the upper left pixel. + * @param width + * the total width of the updated area. + * @param height + * the total height of the updated area. + * @param periodX + * the horizontal separation between pixels. + * @param periodY + * the vertical separation between pixels. + * @param bands + * the number of affected bands. + */ + protected void processThumbnailUpdate(BufferedImage theThumbnail, int minX, int minY, + int width, int height, int periodX, int periodY, int[] bands) { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Processes the end of a thumbnail progressive pass by calling the + * thumbnailPassComplete method on all registered IIOReadUpdateListeners. + * + * @param theThumbnail + * the thumbnail to be updated. + */ + protected void processThumbnailPassComplete(BufferedImage theThumbnail) { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Processes a warning message by calling warningOccurred method of + * registered IIOReadWarningListeners. + * + * @param warning + * the warning. + */ + protected void processWarningOccurred(String warning) { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Processes a warning by calling the warningOccurred method of on all + * registered IIOReadWarningListeners. + * + * @param baseName + * the base name of ResourceBundles. + * @param keyword + * the keyword to index the warning among ResourceBundles. + */ + protected void processWarningOccurred(String baseName, String keyword) { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Resets this ImageReader. + */ + public void reset() { + // def + setInput(null, false); + setLocale(null); + removeAllIIOReadUpdateListeners(); + removeAllIIOReadWarningListeners(); + removeAllIIOReadProgressListeners(); + clearAbortRequest(); + } + + /** + * Disposes of any resources. + */ + public void dispose() { + // do nothing by def + } + + /** + * Gets the region of source image that should be read with the specified + * width, height and ImageReadParam. + * + * @param param + * the ImageReadParam object, or null. + * @param srcWidth + * the source image's width. + * @param srcHeight + * the source image's height. + * @return the Rectangle of source region. + */ + protected static Rectangle getSourceRegion(ImageReadParam param, int srcWidth, int srcHeight) { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Computes the specified source region and the specified destination region + * with the specified the width and height of the source image, an optional + * destination image, and an ImageReadParam. + * + * @param param + * the an ImageReadParam object, or null. + * @param srcWidth + * the source image's width. + * @param srcHeight + * the source image's height. + * @param image + * the destination image. + * @param srcRegion + * the source region. + * @param destRegion + * the destination region. + */ + protected static void computeRegions(ImageReadParam param, int srcWidth, int srcHeight, + BufferedImage image, Rectangle srcRegion, Rectangle destRegion) { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Checks the validity of the source and destination band and is called when + * the reader knows the number of bands of the source image and the number + * of bands of the destination image. + * + * @param param + * the ImageReadParam for reading the Image. + * @param numSrcBands + * the number of bands in the source. + * @param numDstBands + * the number of bands in the destination. + */ + protected static void checkReadParamBandSettings(ImageReadParam param, int numSrcBands, + int numDstBands) { + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Gets the destination image where the decoded data is written. + * + * @param param + * the ImageReadParam. + * @param imageTypes + * the iterator of ImageTypeSpecifier objects. + * @param width + * the width of the image being decoded. + * @param height + * the height of the image being decoded. + * @return the BufferedImage where decoded pixels should be written. + * @throws IIOException + * the IIOException is thrown if there is no suitable + * ImageTypeSpecifier. + */ + protected static BufferedImage getDestination(ImageReadParam param, + Iterator imageTypes, int width, int height) throws IIOException { + throw new UnsupportedOperationException("Not implemented yet"); + } +} diff --git a/app/src/main/java/javax/imageio/ImageTranscoder.java b/app/src/main/java/javax/imageio/ImageTranscoder.java new file mode 100644 index 000000000..632d890f8 --- /dev/null +++ b/app/src/main/java/javax/imageio/ImageTranscoder.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.3 $ + */ + +package javax.imageio; + +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.ImageTypeSpecifier; + +/** + * The ImageTranscoder interface is to be implemented by classes that perform + * image transcoding operations, that is, take images written in one format and + * write them in another format using read/write operations. Some image data can + * be lost in such processes. The ImageTranscoder interface converts metadata + * objects (IIOMetadata) of ImageReader to appropriate metadata object for + * ImageWriter. + * + * @since Android 1.0 + */ +public interface ImageTranscoder { + + /** + * Converts the specified IIOMetadata object using the specified + * ImageWriteParam for obtaining writer's metadata structure. + * + * @param inData + * the IIOMetadata. + * @param param + * the ImageWriteParam. + * @return the IIOMetadata, or null. + */ + IIOMetadata convertStreamMetadata(IIOMetadata inData, ImageWriteParam param); + + /** + * Converts the specified IIOMetadata object using the specified + * ImageWriteParam for obtaining writer's metadata structure and + * ImageTypeSpecifier object for obtaining the layout and color information + * of the image for this metadata. + * + * @param inData + * the IIOMetadata. + * @param imageType + * the ImageTypeSpecifier. + * @param param + * the ImageWriteParam. + * @return the IIOMetadata, or null. + */ + IIOMetadata convertImageMetadata(IIOMetadata inData, ImageTypeSpecifier imageType, + ImageWriteParam param); +} diff --git a/app/src/main/java/javax/imageio/ImageTypeSpecifier.java b/app/src/main/java/javax/imageio/ImageTypeSpecifier.java new file mode 100644 index 000000000..e47e61704 --- /dev/null +++ b/app/src/main/java/javax/imageio/ImageTypeSpecifier.java @@ -0,0 +1,347 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.3 $ + */ + +package javax.imageio; + +import java.awt.image.ColorModel; +import java.awt.image.SampleModel; +import java.awt.image.BufferedImage; +import java.awt.image.RenderedImage; +import java.awt.color.ColorSpace; + +/** + * The ImageTypeSpecifier class performs conversion operations on the + * SampleModel and the ColorModel of an image. + * + * @since Android 1.0 + */ +public class ImageTypeSpecifier { + + /** + * The ColorModel of this ImageTypeSpecifier. + */ + protected ColorModel colorModel; + + /** + * The SampleModel of this ImageTypeSpecifier. + */ + protected SampleModel sampleModel; + + /** + * Instantiates a new ImageTypeSpecifier with the specified ColorModel and + * SampleModel objects. + * + * @param colorModel + * the ColorModel. + * @param sampleModel + * the SampleModel. + */ + public ImageTypeSpecifier(ColorModel colorModel, SampleModel sampleModel) { + if (colorModel == null) { + throw new IllegalArgumentException("color model should not be NULL"); + } + if (sampleModel == null) { + throw new IllegalArgumentException("sample model should not be NULL"); + } + if (!colorModel.isCompatibleSampleModel(sampleModel)) { + throw new IllegalArgumentException("color and sample models are not compatible"); + } + + this.colorModel = colorModel; + this.sampleModel = sampleModel; + } + + /** + * Instantiates a new ImageTypeSpecifier using the specified RenderedImage. + * + * @param renderedImage + * the RenderedImage. + */ + public ImageTypeSpecifier(RenderedImage renderedImage) { + if (renderedImage == null) { + throw new IllegalArgumentException("image should not be NULL"); + } + this.colorModel = renderedImage.getColorModel(); + this.sampleModel = renderedImage.getSampleModel(); + } + + /** + * Creates an ImageTypeSpecifier with the specified DirectColorModel and a + * packed SampleModel. + * + * @param colorSpace + * the ColorSpace. + * @param redMask + * the red mask. + * @param greenMask + * the green mask. + * @param blueMask + * the blue mask. + * @param alphaMask + * the alpha mask. + * @param transferType + * the transfer type. + * @param isAlphaPremultiplied + * the parameter indicates if the color channel is pre-multiplied + * by alpha. + * @return the ImageTypeSpecifier. + */ + public static ImageTypeSpecifier createPacked(ColorSpace colorSpace, int redMask, + int greenMask, int blueMask, int alphaMask, int transferType, + boolean isAlphaPremultiplied) { + throw new UnsupportedOperationException("Not supported yet"); + } + + /** + * Creates an ImageTypeSpecifier with specified ComponentColorModel and a + * PixelInterleavedSampleModel. + * + * @param colorSpace + * the ColorSpace. + * @param bandOffsets + * the band offsets. + * @param dataType + * the data type. + * @param hasAlpha + * the parameter indicates if alpha channel is needed. + * @param isAlphaPremultiplied + * the parameter indicates if the color channel is pre-multiplied + * by alpha. + * @return the ImageTypeSpecifier. + */ + public static ImageTypeSpecifier createInterleaved(ColorSpace colorSpace, int[] bandOffsets, + int dataType, boolean hasAlpha, boolean isAlphaPremultiplied) { + throw new UnsupportedOperationException("Not supported yet"); + } + + /** + * Creates a ImageTypeSpecifier for a image with a BandedSampleModel and a + * ComponentColorModel. + * + * @param colorSpace + * the ColorSpace. + * @param bankIndices + * the bank indices. + * @param bandOffsets + * the band offsets. + * @param dataType + * the data type. + * @param hasAlpha + * the parameter indicates a presence of alpha channel. + * @param isAlphaPremultiplied + * the parameter indicates whether or not color channel is alpha + * pre-multiplied. + * @return the image type specifier + */ + public static ImageTypeSpecifier createBanded(ColorSpace colorSpace, int[] bankIndices, + int[] bandOffsets, int dataType, boolean hasAlpha, boolean isAlphaPremultiplied) { + throw new UnsupportedOperationException("Not supported yet"); + } + + /** + * Creates a ImageTypeSpecifier for a grayscale image. + * + * @param bits + * the number of bits per gray value. + * @param dataType + * the data type. + * @param isSigned + * a signed flag. + * @return the ImageTypeSpecifier. + */ + public static ImageTypeSpecifier createGrayscale(int bits, int dataType, boolean isSigned) { + throw new UnsupportedOperationException("Not supported yet"); + } + + /** + * Creates a ImageTypeSpecifier for a grayscale image. + * + * @param bits + * the number of bits per gray value. + * @param dataType + * the data type. + * @param isSigned + * a signed flag. + * @param isAlphaPremultiplied + * the parameter indicates if color channel is pre-multiplied by + * alpha, or not. + * @return the ImageTypeSpecifier. + */ + public static ImageTypeSpecifier createGrayscale(int bits, int dataType, boolean isSigned, + boolean isAlphaPremultiplied) { + throw new UnsupportedOperationException("Not supported yet"); + } + + /** + * Creates a ImageTypeSpecifier with the indexed image format. + * + * @param redLUT + * the red values of indices. + * @param greenLUT + * the green values of indices. + * @param blueLUT + * the blue values of indices. + * @param alphaLUT + * the alpha values of indices. + * @param bits + * the bits number for each index. + * @param dataType + * the data type. + * @return the ImageTypeSpecifier. + */ + public static ImageTypeSpecifier createIndexed(byte[] redLUT, byte[] greenLUT, byte[] blueLUT, + byte[] alphaLUT, int bits, int dataType) { + throw new UnsupportedOperationException("Not supported yet"); + } + + /** + * Creates the ImageTypeSpecifier from the specified buffered image type. + * + * @param bufferedImageType + * the buffered image type. + * @return the ImageTypeSpecifier. + */ + public static ImageTypeSpecifier createFromBufferedImageType(int bufferedImageType) { + throw new UnsupportedOperationException("Not supported yet"); + } + + /** + * Creates the ImageTypeSpecifier from the specified RenderedImage. + * + * @param image + * the RenderedImage. + * @return the ImageTypeSpecifier. + */ + public static ImageTypeSpecifier createFromRenderedImage(RenderedImage image) { + if (null == image) { + throw new IllegalArgumentException("image should not be NULL"); + } + return new ImageTypeSpecifier(image); + } + + /** + * Gets the BufferedImage type. + * + * @return the BufferedImage type. + */ + public int getBufferedImageType() { + throw new UnsupportedOperationException("Not supported yet"); + } + + /** + * Gets the number of components. + * + * @return the number of components. + */ + public int getNumComponents() { + return colorModel.getNumComponents(); + } + + /** + * Gets the number of bands. + * + * @return the number of bands. + */ + public int getNumBands() { + return sampleModel.getNumBands(); + } + + /** + * Gets the number of bits per the specified band. + * + * @param band + * the index of band. + * @return the number of bits per the specified band. + */ + public int getBitsPerBand(int band) { + if (band < 0 || band >= getNumBands()) { + throw new IllegalArgumentException(); + } + return sampleModel.getSampleSize(band); + } + + /** + * Gets the SampleModel associated with this ImageTypeSpecifier. + * + * @return the SampleModel associated with this ImageTypeSpecifier. + */ + public SampleModel getSampleModel() { + return sampleModel; + } + + /** + * Gets a compatible SampleModel with the specified width and height. + * + * @param width + * the width. + * @param height + * the height. + * @return the SampleModel. + */ + public SampleModel getSampleModel(int width, int height) { + if ((long)width * height > Integer.MAX_VALUE) { + throw new IllegalArgumentException("width * height > Integer.MAX_VALUE"); + } + return sampleModel.createCompatibleSampleModel(width, height); + } + + /** + * Gets the ColorModel associated with this ImageTypeSpecifier. + * + * @return the ColorModel associated with this ImageTypeSpecifier. + */ + public ColorModel getColorModel() { + return colorModel; + } + + /** + * Creates the BufferedImage with the specified width and height and the + * ColorMadel and SampleModel which are specified by this + * ImageTypeSpecifier. + * + * @param width + * the width of the BufferedImage. + * @param height + * the height of the BufferedImage. + * @return the BufferedImage. + */ + public BufferedImage createBufferedImage(int width, int height) { + throw new UnsupportedOperationException("Not supported yet"); + } + + /** + * Compares this ImageTypeSpecifier object with the specified object. + * + * @param o + * the Object to be compared. + * @return true, if the object is an ImageTypeSpecifier with the same data + * as this ImageTypeSpecifier, false otherwise. + */ + @Override + public boolean equals(Object o) { + boolean rt = false; + if (o instanceof ImageTypeSpecifier) { + ImageTypeSpecifier ts = (ImageTypeSpecifier)o; + rt = colorModel.equals(ts.colorModel) && sampleModel.equals(ts.sampleModel); + } + return rt; + } +} diff --git a/app/src/main/java/javax/imageio/ImageWriteParam.java b/app/src/main/java/javax/imageio/ImageWriteParam.java new file mode 100644 index 000000000..d661889b2 --- /dev/null +++ b/app/src/main/java/javax/imageio/ImageWriteParam.java @@ -0,0 +1,664 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.3 $ + */ + +package javax.imageio; + +import java.util.Locale; +import java.awt.*; + +/** + * The ImageWriteParam class provides information to an ImageWriter about how an + * image is to be encoded. + * + * @since Android 1.0 + */ +public class ImageWriteParam extends IIOParam { + + /** + * The Constant MODE_DISABLED indicates that stream is not tiled, + * progressive, or compressed. + */ + public static final int MODE_DISABLED = 0; + + /** + * The Constant MODE_DEFAULT indicates that the stream will be tiled, + * progressive, or compressed according to the plug-in's default. + */ + public static final int MODE_DEFAULT = 1; + + /** + * The Constant MODE_EXPLICIT indicates that the stream will be tiled, + * progressive, or compressed according to current settings which are + * defined by set methods. + */ + public static final int MODE_EXPLICIT = 2; + + /** + * The Constant MODE_COPY_FROM_METADATA indicates that the stream will be + * tiled, progressive, or compressed according to stream or image metadata. + */ + public static final int MODE_COPY_FROM_METADATA = 3; + + /** + * Whether the ImageWriter can write tiles. + */ + protected boolean canWriteTiles = false; + + /** + * The tiling mode. + */ + protected int tilingMode = MODE_COPY_FROM_METADATA; + + /** + * The preferred tile sizes. + */ + protected Dimension[] preferredTileSizes = null; + + /** + * The tiling set. + */ + protected boolean tilingSet = false; + + /** + * The tile width. + */ + protected int tileWidth = 0; + + /** + * The tile height. + */ + protected int tileHeight = 0; + + /** + * Whether the ImageWriter can offset tiles. + */ + protected boolean canOffsetTiles = false; + + /** + * The tile grid x offset. + */ + protected int tileGridXOffset = 0; + + /** + * The tile grid y offset. + */ + protected int tileGridYOffset = 0; + + /** + * Whether the ImageWriter can write in progressive mode. + */ + protected boolean canWriteProgressive = false; + + /** + * The progressive mode. + */ + protected int progressiveMode = MODE_COPY_FROM_METADATA; + + /** + * Whether the ImageWriter can write in compressed mode. + */ + protected boolean canWriteCompressed = false; + + /** + * The compression mode. + */ + protected int compressionMode = MODE_COPY_FROM_METADATA; + + /** + * The compression types. + */ + protected String[] compressionTypes = null; + + /** + * The compression type. + */ + protected String compressionType = null; + + /** + * The compression quality. + */ + protected float compressionQuality = 1.0f; + + /** + * The locale. + */ + protected Locale locale = null; + + /** + * Instantiates a new ImageWriteParam. + */ + protected ImageWriteParam() { + } + + /** + * Instantiates a new ImageWriteParam with the specified Locale. + * + * @param locale + * the Locale. + */ + public ImageWriteParam(Locale locale) { + this.locale = locale; + + } + + /** + * Gets the mode for writing the stream in a progressive sequence. + * + * @return the current progressive mode. + */ + public int getProgressiveMode() { + if (canWriteProgressive()) { + return progressiveMode; + } + throw new UnsupportedOperationException("progressive mode is not supported"); + } + + /** + * Returns true if images can be written using increasing quality passes by + * progressive. + * + * @return true if images can be written using increasing quality passes by + * progressive, false otherwise. + */ + public boolean canWriteProgressive() { + return canWriteProgressive; + } + + /** + * Sets the progressive mode which defines whether the stream contains a + * progressive sequence of increasing quality during writing. The + * progressive mode should be one of the following values: MODE_DISABLED, + * MODE_DEFAULT, or MODE_COPY_FROM_METADATA. + * + * @param mode + * the new progressive mode. + */ + public void setProgressiveMode(int mode) { + if (canWriteProgressive()) { + if (mode < MODE_DISABLED || mode > MODE_COPY_FROM_METADATA || mode == MODE_EXPLICIT) { + throw new IllegalArgumentException("mode is not supported"); + } + this.progressiveMode = mode; + } + throw new UnsupportedOperationException("progressive mode is not supported"); + } + + /** + * Returns true if the writer can use tiles with non zero grid offsets while + * writing. + * + * @return true, if the writer can use tiles with non zero grid offsets + * while writing, false otherwise. + */ + public boolean canOffsetTiles() { + return canOffsetTiles; + } + + /** + * Returns true if this writer can write images with compression. + * + * @return true, if this writer can write images with compression, false + * otherwise. + */ + public boolean canWriteCompressed() { + return canWriteCompressed; + } + + /** + * Returns true if the writer can write tiles. + * + * @return true, if the writer can write tiles, false otherwise. + */ + public boolean canWriteTiles() { + return canWriteTiles; + } + + /** + * Check write compressed. + */ + private final void checkWriteCompressed() { + if (!canWriteCompressed()) { + throw new UnsupportedOperationException("Compression not supported."); + } + } + + /** + * Check compression mode. + */ + private final void checkCompressionMode() { + if (getCompressionMode() != MODE_EXPLICIT) { + throw new IllegalStateException("Compression mode not MODE_EXPLICIT!"); + } + } + + /** + * Check compression type. + */ + private final void checkCompressionType() { + if (getCompressionTypes() != null && getCompressionType() == null) { + throw new IllegalStateException("No compression type set!"); + } + } + + /** + * Gets the compression mode. + * + * @return the compression mode if it's supported. + */ + public int getCompressionMode() { + checkWriteCompressed(); + return compressionMode; + } + + /** + * Gets the an array of supported compression types. + * + * @return the an array of supported compression types. + */ + public String[] getCompressionTypes() { + checkWriteCompressed(); + if (compressionTypes != null) { + return compressionTypes.clone(); + } + return null; + } + + /** + * Gets the current compression type, or returns null. + * + * @return the current compression type, or returns null if it is not set. + */ + public String getCompressionType() { + checkWriteCompressed(); + checkCompressionMode(); + return compressionType; + } + + /** + * Gets a bit rate which represents an estimate of the number of bits of + * output data for each bit of input image data with the specified quality. + * + * @param quality + * the quality. + * @return an estimate of the bit rate, or -1.0F if there is no estimate. + */ + public float getBitRate(float quality) { + checkWriteCompressed(); + checkCompressionMode(); + checkCompressionType(); + if (quality < 0 || quality > 1) { + throw new IllegalArgumentException("Quality out-of-bounds!"); + } + return -1.0f; + } + + /** + * Gets the compression quality. + * + * @return the compression quality. + */ + public float getCompressionQuality() { + checkWriteCompressed(); + checkCompressionMode(); + checkCompressionType(); + return compressionQuality; + } + + /** + * Gets the array of compression quality descriptions. + * + * @return the string array of compression quality descriptions. + */ + public String[] getCompressionQualityDescriptions() { + checkWriteCompressed(); + checkCompressionMode(); + checkCompressionType(); + return null; + } + + /** + * Gets an array of floats which describes compression quality levels. + * + * @return the array of compression quality values. + */ + public float[] getCompressionQualityValues() { + checkWriteCompressed(); + checkCompressionMode(); + checkCompressionType(); + return null; + } + + /** + * Gets the locale of this ImageWriteParam. + * + * @return the locale of this ImageWriteParam. + */ + public Locale getLocale() { + return locale; + } + + /** + * Gets the current compression type using the current Locale. + * + * @return the current compression type using the current Locale. + */ + public String getLocalizedCompressionTypeName() { + checkWriteCompressed(); + checkCompressionMode(); + + String compressionType = getCompressionType(); + if (compressionType == null) { + throw new IllegalStateException("No compression type set!"); + } + return compressionType; + + } + + /** + * Check tiling. + */ + private final void checkTiling() { + if (!canWriteTiles()) { + throw new UnsupportedOperationException("Tiling not supported!"); + } + } + + /** + * Check tiling mode. + */ + private final void checkTilingMode() { + if (getTilingMode() != MODE_EXPLICIT) { + throw new IllegalStateException("Tiling mode not MODE_EXPLICIT!"); + } + } + + /** + * Check tiling params. + */ + private final void checkTilingParams() { + if (!tilingSet) { + throw new IllegalStateException("Tiling parameters not set!"); + } + } + + /** + * Gets the tiling mode if tiling is supported. + * + * @return the tiling mode if tiling is supported. + */ + public int getTilingMode() { + checkTiling(); + return tilingMode; + } + + /** + * Gets an array of Dimensions giving the sizes of the tiles as they are + * encoded in the output file or stream. + * + * @return the preferred tile sizes. + */ + public Dimension[] getPreferredTileSizes() { + checkTiling(); + if (preferredTileSizes == null) { + return null; + } + + Dimension[] retval = new Dimension[preferredTileSizes.length]; + for (int i = 0; i < preferredTileSizes.length; i++) { + retval[i] = new Dimension(retval[i]); + } + return retval; + } + + /** + * Gets the tile grid X offset for encoding. + * + * @return the tile grid X offset for encoding. + */ + public int getTileGridXOffset() { + checkTiling(); + checkTilingMode(); + checkTilingParams(); + return tileGridXOffset; + } + + /** + * Gets the tile grid Y offset for encoding. + * + * @return the tile grid Y offset for encoding. + */ + public int getTileGridYOffset() { + checkTiling(); + checkTilingMode(); + checkTilingParams(); + return tileGridYOffset; + } + + /** + * Gets the tile height in an image as it is written to the output stream. + * + * @return the tile height in an image as it is written to the output + * stream. + */ + public int getTileHeight() { + checkTiling(); + checkTilingMode(); + checkTilingParams(); + return tileHeight; + } + + /** + * Gets the tile width in an image as it is written to the output stream. + * + * @return the tile width in an image as it is written to the output stream. + */ + public int getTileWidth() { + checkTiling(); + checkTilingMode(); + checkTilingParams(); + return tileWidth; + } + + /** + * Checks if the current compression type has lossless compression or not. + * + * @return true, if the current compression type has lossless compression, + * false otherwise. + */ + public boolean isCompressionLossless() { + checkWriteCompressed(); + checkCompressionMode(); + checkCompressionType(); + return true; + } + + /** + * Removes current compression type. + */ + public void unsetCompression() { + checkWriteCompressed(); + checkCompressionMode(); + compressionType = null; + compressionQuality = 1; + } + + /** + * Sets the compression mode to the specified value. The specified mode can + * be one of the predefined constants: MODE_DEFAULT, MODE_DISABLED, + * MODE_EXPLICIT, or MODE_COPY_FROM_METADATA. + * + * @param mode + * the new compression mode to be set. + */ + public void setCompressionMode(int mode) { + checkWriteCompressed(); + switch (mode) { + case MODE_EXPLICIT: { + compressionMode = mode; + unsetCompression(); + break; + } + case MODE_COPY_FROM_METADATA: + case MODE_DISABLED: + case MODE_DEFAULT: { + compressionMode = mode; + break; + } + default: { + throw new IllegalArgumentException("Illegal value for mode!"); + } + } + } + + /** + * Sets the compression quality. The value should be between 0 and 1. + * + * @param quality + * the new compression quality, float value between 0 and 1. + */ + public void setCompressionQuality(float quality) { + checkWriteCompressed(); + checkCompressionMode(); + checkCompressionType(); + if (quality < 0 || quality > 1) { + throw new IllegalArgumentException("Quality out-of-bounds!"); + } + compressionQuality = quality; + } + + /** + * Sets the compression type. The specified string should be one of the + * values returned by getCompressionTypes method. + * + * @param compressionType + * the new compression type. + */ + public void setCompressionType(String compressionType) { + checkWriteCompressed(); + checkCompressionMode(); + + if (compressionType == null) { // Don't check anything + this.compressionType = null; + } else { + String[] compressionTypes = getCompressionTypes(); + if (compressionTypes == null) { + throw new UnsupportedOperationException("No settable compression types"); + } + + for (int i = 0; i < compressionTypes.length; i++) { + if (compressionTypes[i].equals(compressionType)) { + this.compressionType = compressionType; + return; + } + } + + // Compression type is not in the list. + throw new IllegalArgumentException("Unknown compression type!"); + } + } + + /** + * Sets the instruction that tiling should be performed for the image in the + * output stream with the specified parameters. + * + * @param tileWidth + * the tile's width. + * @param tileHeight + * the tile's height. + * @param tileGridXOffset + * the tile grid's x offset. + * @param tileGridYOffset + * the tile grid's y offset. + */ + public void setTiling(int tileWidth, int tileHeight, int tileGridXOffset, int tileGridYOffset) { + checkTiling(); + checkTilingMode(); + + if (!canOffsetTiles() && (tileGridXOffset != 0 || tileGridYOffset != 0)) { + throw new UnsupportedOperationException("Can't offset tiles!"); + } + + if (tileWidth <= 0 || tileHeight <= 0) { + throw new IllegalArgumentException("tile dimensions are non-positive!"); + } + + Dimension preferredTileSizes[] = getPreferredTileSizes(); + if (preferredTileSizes != null) { + for (int i = 0; i < preferredTileSizes.length; i += 2) { + Dimension minSize = preferredTileSizes[i]; + Dimension maxSize = preferredTileSizes[i + 1]; + if (tileWidth < minSize.width || tileWidth > maxSize.width + || tileHeight < minSize.height || tileHeight > maxSize.height) { + throw new IllegalArgumentException("Illegal tile size!"); + } + } + } + + tilingSet = true; + this.tileWidth = tileWidth; + this.tileHeight = tileHeight; + this.tileGridXOffset = tileGridXOffset; + this.tileGridYOffset = tileGridYOffset; + } + + /** + * Clears all tiling settings. + */ + public void unsetTiling() { + checkTiling(); + checkTilingMode(); + + tilingSet = false; + tileWidth = 0; + tileHeight = 0; + tileGridXOffset = 0; + tileGridYOffset = 0; + } + + /** + * Sets the tiling mode. The specified mode should be one of the following + * values: MODE_DISABLED, MODE_DEFAULT, MODE_EXPLICIT, or + * MODE_COPY_FROM_METADATA. + * + * @param mode + * the new tiling mode. + */ + public void setTilingMode(int mode) { + checkTiling(); + + switch (mode) { + case MODE_EXPLICIT: { + tilingMode = mode; + unsetTiling(); + break; + } + case MODE_COPY_FROM_METADATA: + case MODE_DISABLED: + case MODE_DEFAULT: { + tilingMode = mode; + break; + } + default: { + throw new IllegalArgumentException("Illegal value for mode!"); + } + } + } +} diff --git a/app/src/main/java/javax/imageio/ImageWriter.java b/app/src/main/java/javax/imageio/ImageWriter.java new file mode 100644 index 000000000..86879e040 --- /dev/null +++ b/app/src/main/java/javax/imageio/ImageWriter.java @@ -0,0 +1,1001 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.3 $ + */ + +package javax.imageio; + +import java.awt.Dimension; +import java.awt.Rectangle; +import java.awt.image.BufferedImage; +import java.awt.image.Raster; +import java.awt.image.RenderedImage; +import java.io.IOException; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +import javax.imageio.event.IIOWriteProgressListener; +import javax.imageio.event.IIOWriteWarningListener; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.spi.ImageWriterSpi; + +/** + * The ImageWriter class is an abstract class for encoding images. ImageWriter + * objects are instantiated by the service provider interface, ImageWriterSpi + * class, for the specific format. ImageWriterSpi class should be registered + * with the IIORegistry, which uses them for format recognition and presentation + * of available format readers and writers. + * + * @since Android 1.0 + */ +public abstract class ImageWriter implements ImageTranscoder { + + /** + * The available locales. + */ + protected Locale[] availableLocales; + + /** + * The locale. + */ + protected Locale locale; + + /** + * The originating provider. + */ + protected ImageWriterSpi originatingProvider; + + /** + * The output. + */ + protected Object output; + + /** + * The progress listeners. + */ + protected List progressListeners; + + /** + * The warning listeners. + */ + protected List warningListeners; + + /** + * The warning locales. + */ + protected List warningLocales; + + // Indicates that abort operation is requested + // Abort mechanism should be thread-safe + /** The aborted. */ + private boolean aborted; + + /** + * Instantiates a new ImageWriter. + * + * @param originatingProvider + * the ImageWriterSpi which instantiates this ImageWriter. + */ + protected ImageWriter(ImageWriterSpi originatingProvider) { + this.originatingProvider = originatingProvider; + } + + public abstract IIOMetadata convertStreamMetadata(IIOMetadata iioMetadata, + ImageWriteParam imageWriteParam); + + public abstract IIOMetadata convertImageMetadata(IIOMetadata iioMetadata, + ImageTypeSpecifier imageTypeSpecifier, ImageWriteParam imageWriteParam); + + /** + * Gets the ImageWriterSpi which instantiated this ImageWriter. + * + * @return the ImageWriterSpi. + */ + public ImageWriterSpi getOriginatingProvider() { + return originatingProvider; + } + + /** + * Processes the start of an image read by calling their imageStarted method + * of registered IIOWriteProgressListeners. + * + * @param imageIndex + * the image index. + */ + protected void processImageStarted(int imageIndex) { + if (null != progressListeners) { + for (IIOWriteProgressListener listener : progressListeners) { + listener.imageStarted(this, imageIndex); + } + } + } + + /** + * Processes the current percentage of image completion by calling + * imageProgress method of registered IIOWriteProgressListener. + * + * @param percentageDone + * the percentage done. + */ + protected void processImageProgress(float percentageDone) { + if (null != progressListeners) { + for (IIOWriteProgressListener listener : progressListeners) { + listener.imageProgress(this, percentageDone); + } + } + } + + /** + * Processes image completion by calling imageComplete method of registered + * IIOWriteProgressListeners. + */ + protected void processImageComplete() { + if (null != progressListeners) { + for (IIOWriteProgressListener listener : progressListeners) { + listener.imageComplete(this); + } + } + } + + /** + * Processes a warning message by calling warningOccurred method of + * registered IIOWriteWarningListeners. + * + * @param imageIndex + * the image index. + * @param warning + * the warning. + */ + protected void processWarningOccurred(int imageIndex, String warning) { + if (null == warning) { + throw new NullPointerException("warning message should not be NULL"); + } + if (null != warningListeners) { + for (IIOWriteWarningListener listener : warningListeners) { + listener.warningOccurred(this, imageIndex, warning); + } + } + } + + /** + * Processes a warning message by calling warningOccurred method of + * registered IIOWriteWarningListeners with string from ResourceBundle. + * + * @param imageIndex + * the image index. + * @param bundle + * the name of ResourceBundle. + * @param key + * the keyword. + */ + protected void processWarningOccurred(int imageIndex, String bundle, String key) { + if (warningListeners != null) { // Don't check the parameters + return; + } + + if (bundle == null) { + throw new IllegalArgumentException("baseName == null!"); + } + if (key == null) { + throw new IllegalArgumentException("keyword == null!"); + } + + // Get the context class loader and try to locate the bundle with it + // first + ClassLoader contextClassloader = AccessController + .doPrivileged(new PrivilegedAction() { + public ClassLoader run() { + return Thread.currentThread().getContextClassLoader(); + } + }); + + // Iterate through both listeners and locales + int n = warningListeners.size(); + for (int i = 0; i < n; i++) { + IIOWriteWarningListener listener = warningListeners.get(i); + Locale locale = warningLocales.get(i); + + // Now try to get the resource bundle + ResourceBundle rb; + try { + rb = ResourceBundle.getBundle(bundle, locale, contextClassloader); + } catch (MissingResourceException e) { + try { + rb = ResourceBundle.getBundle(bundle, locale); + } catch (MissingResourceException e1) { + throw new IllegalArgumentException("Bundle not found!"); + } + } + + try { + String warning = rb.getString(key); + listener.warningOccurred(this, imageIndex, warning); + } catch (MissingResourceException e) { + throw new IllegalArgumentException("Resource is missing!"); + } catch (ClassCastException e) { + throw new IllegalArgumentException("Resource is not a String!"); + } + } + } + + /** + * Sets the specified Object to the output of this ImageWriter. + * + * @param output + * the Object which represents destination, it can be + * ImageOutputStream or other objects. + */ + public void setOutput(Object output) { + if (output != null) { + ImageWriterSpi spi = getOriginatingProvider(); + if (null != spi) { + Class[] outTypes = spi.getOutputTypes(); + boolean supported = false; + for (Class element : outTypes) { + if (element.isInstance(output)) { + supported = true; + break; + } + } + if (!supported) { + throw new IllegalArgumentException("output " + output + " is not supported"); + } + } + } + this.output = output; + } + + /** + * Writes a completed image stream that contains the specified image, + * default metadata, and thumbnails to the output. + * + * @param image + * the specified image to be written. + * @throws IOException + * if an I/O exception has occurred during writing. + */ + public void write(IIOImage image) throws IOException { + write(null, image, null); + } + + /** + * Writes a completed image stream that contains the specified rendered + * image, default metadata, and thumbnails to the output. + * + * @param image + * the specified RenderedImage to be written. + * @throws IOException + * if an I/O exception has occurred during writing. + */ + public void write(RenderedImage image) throws IOException { + write(null, new IIOImage(image, null, null), null); + } + + /** + * Writes a completed image stream that contains the specified image, + * metadata and thumbnails to the output. + * + * @param streamMetadata + * the stream metadata, or null. + * @param image + * the specified image to be written, if canWriteRaster() method + * returns false, then Image must contain only RenderedImage. + * @param param + * the ImageWriteParam, or null. + * @throws IOException + * if an error occurs during writing. + */ + public abstract void write(IIOMetadata streamMetadata, IIOImage image, ImageWriteParam param) + throws IOException; + + /** + * Disposes of any resources. + */ + public void dispose() { + // def impl. does nothing according to the spec. + } + + /** + * Requests an abort operation for current writing operation. + */ + public synchronized void abort() { + aborted = true; + } + + /** + * Checks whether or not a request to abort the current write operation has + * been made successfully. + * + * @return true, if the request to abort the current write operation has + * been made successfully, false otherwise. + */ + protected synchronized boolean abortRequested() { + return aborted; + } + + /** + * Clears all previous abort request, and abortRequested returns false after + * calling this method. + */ + protected synchronized void clearAbortRequest() { + aborted = false; + } + + /** + * Adds the IIOWriteProgressListener listener. + * + * @param listener + * the IIOWriteProgressListener listener. + */ + public void addIIOWriteProgressListener(IIOWriteProgressListener listener) { + if (listener == null) { + return; + } + + if (progressListeners == null) { + progressListeners = new ArrayList(); + } + + progressListeners.add(listener); + } + + /** + * Adds the IIOWriteWarningListener. + * + * @param listener + * the IIOWriteWarningListener listener. + */ + public void addIIOWriteWarningListener(IIOWriteWarningListener listener) { + if (listener == null) { + return; + } + + if (warningListeners == null) { + warningListeners = new ArrayList(); + warningLocales = new ArrayList(); + } + + warningListeners.add(listener); + warningLocales.add(getLocale()); + } + + /** + * Gets the output object that was set by setOutput method. + * + * @return the output object such as ImageOutputStream, or null if it is not + * set. + */ + public Object getOutput() { + return output; + } + + /** + * Check output return false. + * + * @return true, if successful. + */ + private final boolean checkOutputReturnFalse() { + if (getOutput() == null) { + throw new IllegalStateException("getOutput() == null!"); + } + return false; + } + + /** + * Unsupported operation. + */ + private final void unsupportedOperation() { + if (getOutput() == null) { + throw new IllegalStateException("getOutput() == null!"); + } + throw new UnsupportedOperationException("Unsupported write variant!"); + } + + /** + * Returns true if a new empty image can be inserted at the specified index. + * + * @param imageIndex + * the specified index of image. + * @return true if a new empty image can be inserted at the specified index, + * false otherwise. + * @throws IOException + * Signals that an I/O exception has occurred. + */ + public boolean canInsertEmpty(int imageIndex) throws IOException { + return checkOutputReturnFalse(); + } + + /** + * Returns true if a new image can be inserted at the specified index. + * + * @param imageIndex + * the specified index of image. + * @return true if a new image can be inserted at the specified index, false + * otherwise. + * @throws IOException + * Signals that an I/O exception has occurred. + */ + public boolean canInsertImage(int imageIndex) throws IOException { + return checkOutputReturnFalse(); + } + + /** + * Returns true if the image with the specified index can be removed. + * + * @param imageIndex + * the specified index of image. + * @return true if the image with the specified index can be removed, false + * otherwise. + * @throws IOException + * Signals that an I/O exception has occurred. + */ + public boolean canRemoveImage(int imageIndex) throws IOException { + return checkOutputReturnFalse(); + } + + /** + * Returns true if metadata of the image with the specified index can be + * replaced. + * + * @param imageIndex + * the specified image index. + * @return true if metadata of the image with the specified index can be + * replaced, false otherwise. + * @throws IOException + * if an I/O exception has occurred. + */ + public boolean canReplaceImageMetadata(int imageIndex) throws IOException { + return checkOutputReturnFalse(); + } + + /** + * Returns true if pixels of the image with the specified index can be + * replaced by the replacePixels methods. + * + * @param imageIndex + * the image's index. + * @return true if pixels of the image with the specified index can be + * replaced by the replacePixels methods, false otherwise. + * @throws IOException + * Signals that an I/O exception has occurred. + */ + public boolean canReplacePixels(int imageIndex) throws IOException { + return checkOutputReturnFalse(); + } + + /** + * Returns true if the stream metadata presented in the output can be + * removed. + * + * @return true if the stream metadata presented in the output can be + * removed, false otherwise. + * @throws IOException + * if an I/O exception has occurred. + */ + public boolean canReplaceStreamMetadata() throws IOException { + return checkOutputReturnFalse(); + } + + /** + * Returns true if the writing of a complete image stream which contains a + * single image is supported with undefined pixel values and associated + * metadata and thumbnails to the output. + * + * @return true if the writing of a complete image stream which contains a + * single image is supported, false otherwise. + * @throws IOException + * if an I/O exception has occurred. + */ + public boolean canWriteEmpty() throws IOException { + return checkOutputReturnFalse(); + } + + /** + * Returns true if the methods which taken an IIOImageParameter can deal + * with a Raster source image. + * + * @return true if the methods which taken an IIOImageParameter can deal + * with a Raster source image, false otherwise. + */ + public boolean canWriteRasters() { + return false; + } + + /** + * Returns true if the writer can add an image to stream that already + * contains header information. + * + * @return if the writer can add an image to stream that already contains + * header information, false otherwise. + */ + public boolean canWriteSequence() { + return false; + } + + /** + * Ends the insertion of a new image. + * + * @throws IOException + * if an I/O exception has occurred. + */ + public void endInsertEmpty() throws IOException { + unsupportedOperation(); + } + + /** + * Ends the replace pixels operation. + * + * @throws IOException + * if an I/O exception has occurred. + */ + public void endReplacePixels() throws IOException { + unsupportedOperation(); + } + + /** + * Ends an empty write operation. + * + * @throws IOException + * if an I/O exception has occurred. + */ + public void endWriteEmpty() throws IOException { + unsupportedOperation(); + } + + /** + * Ends the sequence of write operations. + * + * @throws IOException + * if an I/O exception has occurred. + */ + public void endWriteSequence() throws IOException { + unsupportedOperation(); + } + + /** + * Gets an array of available locales. + * + * @return an of array available locales. + */ + public Locale[] getAvailableLocales() { + if (availableLocales == null) { + return null; + } + + return availableLocales.clone(); + } + + /** + * Gets an IIOMetadata object that contains default values for encoding an + * image with the specified type. + * + * @param imageType + * the ImageTypeSpecifier. + * @param param + * the ImageWriteParam. + * @return the IIOMetadata object. + */ + public abstract IIOMetadata getDefaultImageMetadata(ImageTypeSpecifier imageType, + ImageWriteParam param); + + /** + * Gets an IIOMetadata object that contains default values for encoding a + * stream of images. + * + * @param param + * the ImageWriteParam. + * @return the IIOMetadata object. + */ + public abstract IIOMetadata getDefaultStreamMetadata(ImageWriteParam param); + + /** + * Gets the current locale of this ImageWriter. + * + * @return the current locale of this ImageWriter. + */ + public Locale getLocale() { + return locale; + } + + /** + * Gets the default write param. Gets a new ImageWriteParam object for this + * ImageWriter with the current Locale. + * + * @return a new ImageWriteParam object for this ImageWriter. + */ + public ImageWriteParam getDefaultWriteParam() { + return new ImageWriteParam(getLocale()); + } + + /** + * Gets the number of thumbnails supported by the format being written with + * supported image type, image write parameters, stream, and image metadata + * objects. + * + * @param imageType + * the ImageTypeSpecifier. + * @param param + * the image's parameters. + * @param streamMetadata + * the stream metadata. + * @param imageMetadata + * the image metadata. + * @return the number of thumbnails supported. + */ + public int getNumThumbnailsSupported(ImageTypeSpecifier imageType, ImageWriteParam param, + IIOMetadata streamMetadata, IIOMetadata imageMetadata) { + return 0; + } + + /** + * Gets the preferred thumbnail sizes. Gets an array of Dimensions with the + * sizes for thumbnail images as they are encoded in the output file or + * stream. + * + * @param imageType + * the ImageTypeSpecifier. + * @param param + * the ImageWriteParam. + * @param streamMetadata + * the stream metadata. + * @param imageMetadata + * the image metadata. + * @return the preferred thumbnail sizes. + */ + public Dimension[] getPreferredThumbnailSizes(ImageTypeSpecifier imageType, + ImageWriteParam param, IIOMetadata streamMetadata, IIOMetadata imageMetadata) { + return null; + } + + /** + * Prepares insertion of an empty image by requesting the insertion of a new + * image into an existing image stream. + * + * @param imageIndex + * the image index. + * @param imageType + * the image type. + * @param width + * the width of the image. + * @param height + * the height of the image. + * @param imageMetadata + * the image metadata, or null. + * @param thumbnails + * the array thumbnails for this image, or null. + * @param param + * the ImageWriteParam, or null. + * @throws IOException + * if an I/O exception has occurred. + */ + public void prepareInsertEmpty(int imageIndex, ImageTypeSpecifier imageType, int width, + int height, IIOMetadata imageMetadata, List thumbnails, + ImageWriteParam param) throws IOException { + unsupportedOperation(); + } + + /** + * Prepares the writer to call the replacePixels method for the specified + * region. + * + * @param imageIndex + * the image's index. + * @param region + * the specified region. + * @throws IOException + * if an I/O exception has occurred. + */ + public void prepareReplacePixels(int imageIndex, Rectangle region) throws IOException { + unsupportedOperation(); + } + + /** + * Prepares the writer for writing an empty image by beginning the process + * of writing a complete image stream that contains a single image with + * undefined pixel values, metadata and thumbnails, to the output. + * + * @param streamMetadata + * the stream metadata. + * @param imageType + * the image type. + * @param width + * the width of the image. + * @param height + * the height of the image. + * @param imageMetadata + * the image's metadata, or null. + * @param thumbnails + * the image's thumbnails, or null. + * @param param + * the image's parameters, or null. + * @throws IOException + * if an I/O exception has occurred. + */ + public void prepareWriteEmpty(IIOMetadata streamMetadata, ImageTypeSpecifier imageType, + int width, int height, IIOMetadata imageMetadata, + List thumbnails, ImageWriteParam param) throws IOException { + unsupportedOperation(); + } + + /** + * Prepares a stream to accept calls of writeToSequence method using the + * metadata object. + * + * @param streamMetadata + * the stream metadata. + * @throws IOException + * if an I/O exception has occurred. + */ + public void prepareWriteSequence(IIOMetadata streamMetadata) throws IOException { + unsupportedOperation(); + } + + /** + * Processes the completion of a thumbnail read by calling their + * thumbnailComplete method of registered IIOWriteProgressListeners. + */ + protected void processThumbnailComplete() { + if (progressListeners != null) { + for (IIOWriteProgressListener listener : progressListeners) { + listener.thumbnailComplete(this); + } + } + } + + /** + * Processes the current percentage of thumbnail completion by calling their + * thumbnailProgress method of registered IIOWriteProgressListeners. + * + * @param percentageDone + * the percentage done. + */ + protected void processThumbnailProgress(float percentageDone) { + if (progressListeners != null) { + for (IIOWriteProgressListener listener : progressListeners) { + listener.thumbnailProgress(this, percentageDone); + } + } + } + + /** + * Processes the start of a thumbnail read by calling thumbnailStarted + * method of registered IIOWriteProgressListeners. + * + * @param imageIndex + * the image index. + * @param thumbnailIndex + * the thumbnail index. + */ + protected void processThumbnailStarted(int imageIndex, int thumbnailIndex) { + if (progressListeners != null) { + for (IIOWriteProgressListener listener : progressListeners) { + listener.thumbnailStarted(this, imageIndex, thumbnailIndex); + } + } + } + + /** + * Processes that the writing has been aborted by calling writeAborted + * method of registered IIOWriteProgressListeners. + */ + protected void processWriteAborted() { + if (progressListeners != null) { + for (IIOWriteProgressListener listener : progressListeners) { + listener.writeAborted(this); + } + } + } + + /** + * Removes the all IIOWriteProgressListener listeners. + */ + public void removeAllIIOWriteProgressListeners() { + progressListeners = null; + } + + /** + * Removes the all IIOWriteWarningListener listeners. + */ + public void removeAllIIOWriteWarningListeners() { + warningListeners = null; + warningLocales = null; + } + + /** + * Removes the specified IIOWriteProgressListener listener. + * + * @param listener + * the registered IIOWriteProgressListener to be removed. + */ + public void removeIIOWriteProgressListener(IIOWriteProgressListener listener) { + if (progressListeners != null && listener != null) { + if (progressListeners.remove(listener) && progressListeners.isEmpty()) { + progressListeners = null; + } + } + } + + /** + * Removes the specified IIOWriteWarningListener listener. + * + * @param listener + * the registered IIOWriteWarningListener listener to be removed. + */ + public void removeIIOWriteWarningListener(IIOWriteWarningListener listener) { + if (warningListeners == null || listener == null) { + return; + } + + int idx = warningListeners.indexOf(listener); + if (idx > -1) { + warningListeners.remove(idx); + warningLocales.remove(idx); + + if (warningListeners.isEmpty()) { + warningListeners = null; + warningLocales = null; + } + } + } + + /** + * Removes the image with the specified index from the stream. + * + * @param imageIndex + * the image's index. + * @throws IOException + * if an I/O exception has occurred. + */ + public void removeImage(int imageIndex) throws IOException { + unsupportedOperation(); + } + + /** + * Replaces image metadata of the image with specified index. + * + * @param imageIndex + * the image's index. + * @param imageMetadata + * the image metadata. + * @throws IOException + * if an I/O exception has occurred. + */ + public void replaceImageMetadata(int imageIndex, IIOMetadata imageMetadata) throws IOException { + unsupportedOperation(); + } + + /** + * Replaces a part of an image presented in the output with the specified + * RenderedImage. + * + * @param image + * the RenderedImage. + * @param param + * the ImageWriteParam. + * @throws IOException + * if an I/O exception has occurred. + */ + public void replacePixels(RenderedImage image, ImageWriteParam param) throws IOException { + unsupportedOperation(); + } + + /** + * Replaces a part of an image presented in the output with the specified + * Raster. + * + * @param raster + * the Raster. + * @param param + * the ImageWriteParam. + * @throws IOException + * if an I/O exception has occurred. + */ + public void replacePixels(Raster raster, ImageWriteParam param) throws IOException { + unsupportedOperation(); + } + + /** + * Replaces the stream metadata of the output with new IIOMetadata. + * + * @param streamMetadata + * the new stream metadata. + * @throws IOException + * if an I/O exception has occurred. + */ + public void replaceStreamMetadata(IIOMetadata streamMetadata) throws IOException { + unsupportedOperation(); + } + + /** + * Sets the locale of this ImageWriter. + * + * @param locale + * the new locale. + */ + public void setLocale(Locale locale) { + if (locale == null) { + this.locale = null; + return; + } + + Locale[] locales = getAvailableLocales(); + boolean validLocale = false; + if (locales != null) { + for (int i = 0; i < locales.length; i++) { + if (locale.equals(locales[i])) { + validLocale = true; + break; + } + } + } + + if (validLocale) { + this.locale = locale; + } else { + throw new IllegalArgumentException("Invalid locale!"); + } + } + + /** + * Resets this ImageWriter. + */ + public void reset() { + setOutput(null); + setLocale(null); + removeAllIIOWriteWarningListeners(); + removeAllIIOWriteProgressListeners(); + clearAbortRequest(); + } + + /** + * Inserts image into existing output stream. + * + * @param imageIndex + * the image index where an image will be written. + * @param image + * the specified image to be written. + * @param param + * the ImageWriteParam, or null. + * @throws IOException + * if an I/O exception has occurred. + */ + public void writeInsert(int imageIndex, IIOImage image, ImageWriteParam param) + throws IOException { + unsupportedOperation(); + } + + /** + * Writes the specified image to the sequence. + * + * @param image + * the image to be written. + * @param param + * the ImageWriteParam, or null. + * @throws IOException + * if an I/O exception has occurred during writing. + */ + public void writeToSequence(IIOImage image, ImageWriteParam param) throws IOException { + unsupportedOperation(); + } +} diff --git a/app/src/main/java/javax/imageio/event/IIOReadProgressListener.java b/app/src/main/java/javax/imageio/event/IIOReadProgressListener.java new file mode 100644 index 000000000..294489639 --- /dev/null +++ b/app/src/main/java/javax/imageio/event/IIOReadProgressListener.java @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Sergey I. Salishev + * @version $Revision: 1.2 $ + */ + +package javax.imageio.event; + +import java.util.EventListener; +import javax.imageio.ImageReader; + +/** + * The IIOReadProgressListener interface notifies callers about the progress of + * the image and thumbnail reading methods. + * + * @since Android 1.0 + */ +public interface IIOReadProgressListener extends EventListener { + + /** + * Notifies this listener that the image reading has been completed. + * + * @param source + * the ImageReader object which calls this method. + */ + void imageComplete(ImageReader source); + + /** + * Notifies this listener about the degree of completion of the read call. + * + * @param source + * the ImageReader object which calls this method. + * @param percentageDone + * the percentage of decoding done. + */ + void imageProgress(ImageReader source, float percentageDone); + + /** + * Notifies this listener that an image read operation has been started. + * + * @param source + * the ImageReader object which calls this method. + * @param imageIndex + * the index of the image in an input file or stream to be read. + */ + void imageStarted(ImageReader source, int imageIndex); + + /** + * Notifies this listener that a read operation has been aborted. + * + * @param source + * the ImageReader object which calls this method. + */ + void readAborted(ImageReader source); + + /** + * Notifies this listener that a sequence of read operations has been + * completed. + * + * @param source + * the ImageReader object which calls this method. + */ + void sequenceComplete(ImageReader source); + + /** + * Notifies this listener that a sequence of read operation has been + * started. + * + * @param source + * the ImageReader object which calls this method. + * @param minIndex + * the index of the first image to be read. + */ + void sequenceStarted(ImageReader source, int minIndex); + + /** + * Notifies that a thumbnail read operation has been completed. + * + * @param source + * the ImageReader object which calls this method. + */ + void thumbnailComplete(ImageReader source); + + /** + * Notifies this listener about the degree of completion of the read call. + * + * @param source + * the ImageReader object which calls this method. + * @param percentageDone + * the percentage of decoding done. + */ + void thumbnailProgress(ImageReader source, float percentageDone); + + /** + * Notifies this listener that a thumbnail reading operation has been + * started. + * + * @param source + * the ImageReader object which calls this method. + * @param imageIndex + * the index of the image in an input file or stream to be read. + * @param thumbnailIndex + * the index of the thumbnail to be read. + */ + void thumbnailStarted(ImageReader source, int imageIndex, int thumbnailIndex); +} diff --git a/app/src/main/java/javax/imageio/event/IIOReadUpdateListener.java b/app/src/main/java/javax/imageio/event/IIOReadUpdateListener.java new file mode 100644 index 000000000..49bdbcb41 --- /dev/null +++ b/app/src/main/java/javax/imageio/event/IIOReadUpdateListener.java @@ -0,0 +1,182 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Sergey I. Salishev + * @version $Revision: 1.2 $ + */ + +package javax.imageio.event; + +import java.awt.image.BufferedImage; +import java.util.EventListener; +import javax.imageio.ImageReader; + +/* + * @author Sergey I. Salishev + * @version $Revision: 1.2 $ + */ + +/** + * The IIOReadUpdateListener interface provides functionality to receive + * notification of pixel updates during image and thumbnail reading operations. + * + * @since Android 1.0 + */ +public interface IIOReadUpdateListener extends EventListener { + + /** + * Notifies this listener that the specified area of the image has been + * updated. + * + * @param source + * the ImageReader object which calls this method. + * @param theImage + * the image to be updated. + * @param minX + * the minimum X coordinate of the pixels in the updated area. + * @param minY + * the minimum Y coordinate of the pixels in the updated area. + * @param width + * the width of updated area. + * @param height + * the height of updated area. + * @param periodX + * the horizontal spacing period between updated pixels, if it + * equals 1, there is no space between pixels. + * @param periodY + * the vertical spacing period between updated pixels, if it + * equals 1, there is no space between pixels. + * @param bands + * the array of integer values indicating the bands being + * updated. + */ + void imageUpdate(ImageReader source, BufferedImage theImage, int minX, int minY, int width, + int height, int periodX, int periodY, int[] bands); + + /** + * Notifies this listener that the current read operation has completed a + * progressive pass. + * + * @param source + * the ImageReader object which calls this method. + * @param theImage + * the image to be updated. + */ + void passComplete(ImageReader source, BufferedImage theImage); + + /** + * Notifies this listener that the current read operation has begun a + * progressive pass. + * + * @param source + * the ImageReader object which calls this method. + * @param theImage + * the image to be updated. + * @param pass + * the number of the pass. + * @param minPass + * the index of the first pass that will be decoded. + * @param maxPass + * the index of the last pass that will be decoded. + * @param minX + * the minimum X coordinate of the pixels in the updated area. + * @param minY + * the minimum Y coordinate of the pixels in the updated area. + * @param periodX + * the horizontal spacing period between updated pixels, if it + * equals 1, there is no space between pixels. + * @param periodY + * the vertical spacing period between updated pixels, if it + * equals 1, there is no space between pixels. + * @param bands + * the array of integer values indicating the bands being + * updated. + */ + void passStarted(ImageReader source, BufferedImage theImage, int pass, int minPass, + int maxPass, int minX, int minY, int periodX, int periodY, int[] bands); + + /** + * Notifies this listener that the current thumbnail read operation has + * completed a progressive pass. + * + * @param source + * the ImageReader object which calls this method. + * @param theImage + * the thumbnail to be updated. + */ + void thumbnailPassComplete(ImageReader source, BufferedImage theImage); + + /** + * Notifies this listener that the current thumbnail read operation has + * begun a progressive pass. + * + * @param source + * the ImageReader object which calls this method. + * @param theThumbnail + * the thumbnail to be updated. + * @param pass + * the number of the pass. + * @param minPass + * the index of the first pass that will be decoded. + * @param maxPass + * the index of the last pass that will be decoded. + * @param minX + * the minimum X coordinate of the pixels in the updated area. + * @param minY + * the minimum Y coordinate of the pixels in the updated area. + * @param periodX + * the horizontal spacing period between updated pixels, if it + * equals 1, there is no space between pixels. + * @param periodY + * the vertical spacing period between updated pixels, if it + * equals 1, there is no space between pixels. + * @param bands + * the array of integer values indicating the bands being + * updated. + */ + void thumbnailPassStarted(ImageReader source, BufferedImage theThumbnail, int pass, + int minPass, int maxPass, int minX, int minY, int periodX, int periodY, int[] bands); + + /** + * Notifies this listener that a specified area of a thumbnail image has + * been updated. + * + * @param source + * the ImageReader object which calls this method. + * @param theThumbnail + * the thumbnail to be updated. + * @param minX + * the minimum X coordinate of the pixels in the updated area. + * @param minY + * the minimum Y coordinate of the pixels in the updated area. + * @param width + * the width of updated area. + * @param height + * the height of updated area. + * @param periodX + * the horizontal spacing period between updated pixels, if it + * equals 1, there is no space between pixels. + * @param periodY + * the vertical spacing period between updated pixels, if it + * equals 1, there is no space between pixels. + * @param bands + * the array of integer values indicating the bands being + * updated. + */ + void thumbnailUpdate(ImageReader source, BufferedImage theThumbnail, int minX, int minY, + int width, int height, int periodX, int periodY, int[] bands); +} diff --git a/app/src/main/java/javax/imageio/event/IIOReadWarningListener.java b/app/src/main/java/javax/imageio/event/IIOReadWarningListener.java new file mode 100644 index 000000000..318a5df46 --- /dev/null +++ b/app/src/main/java/javax/imageio/event/IIOReadWarningListener.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Sergey I. Salishev + * @version $Revision: 1.2 $ + */ + +package javax.imageio.event; + +import java.util.EventListener; +import javax.imageio.ImageReader; + +/* + * @author Sergey I. Salishev + * @version $Revision: 1.2 $ + */ + +/** + * The IIOReadWarningListener provides methods to receive notification of + * warning messages generated by image and thumbnail reading methods. + * + * @since Android 1.0 + */ +public interface IIOReadWarningListener extends EventListener { + + /** + * Notifies this listener about a warning (non-fatal error) during decoding. + * + * @param source + * the ImageReader object which calls this method. + * @param warning + * the string describing the warning. + */ + public void warningOccurred(ImageReader source, String warning); +} diff --git a/app/src/main/java/javax/imageio/event/IIOWriteProgressListener.java b/app/src/main/java/javax/imageio/event/IIOWriteProgressListener.java new file mode 100644 index 000000000..4a2c595ab --- /dev/null +++ b/app/src/main/java/javax/imageio/event/IIOWriteProgressListener.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.3 $ + */ + +package javax.imageio.event; + +import javax.imageio.ImageWriter; +import java.util.EventListener; + +/** + * The IIOWriteProgressListener interface provides methods to receive + * notification about the progress of the image and thumbnail writing methods. + * + * @since Android 1.0 + */ +public interface IIOWriteProgressListener extends EventListener { + + /** + * Notifies this listener that an image write operation has been started. + * + * @param source + * the ImageWriter object which calls this method. + * @param imageIndex + * the index of the image being written. + */ + void imageStarted(ImageWriter source, int imageIndex); + + /** + * Notifies this listener about the degree of completion of the write call. + * + * @param source + * the ImageWriter object which calls this method. + * @param percentageDone + * the percentage of encoding done. + */ + void imageProgress(ImageWriter source, float percentageDone); + + /** + * Notifies this listener that the image writing has been completed. + * + * @param source + * the ImageWriter object which calls this method. + */ + void imageComplete(ImageWriter source); + + /** + * Notifies this listener that a thumbnail write operation has been started. + * + * @param source + * the ImageWriter object which calls this method. + * @param imageIndex + * the index of the image being written. + * @param thumbnailIndex + * the index of the thumbnail being written. + */ + void thumbnailStarted(ImageWriter source, int imageIndex, int thumbnailIndex); + + /** + * Notifies this listener about the degree of completion of the write call. + * + * @param source + * the ImageWriter object which calls this method. + * @param percentageDone + * the percentage of encoding done. + */ + void thumbnailProgress(ImageWriter source, float percentageDone); + + /** + * Notifies this listener that a thumbnail write operation has been + * completed. + * + * @param source + * the ImageWriter object which calls this method. + */ + void thumbnailComplete(ImageWriter source); + + /** + * Notifies this listener that writing operation has been aborted. + * + * @param source + * the ImageWriter object which calls this method. + */ + void writeAborted(ImageWriter source); +} diff --git a/app/src/main/java/javax/imageio/event/IIOWriteWarningListener.java b/app/src/main/java/javax/imageio/event/IIOWriteWarningListener.java new file mode 100644 index 000000000..8ee41cddd --- /dev/null +++ b/app/src/main/java/javax/imageio/event/IIOWriteWarningListener.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.3 $ + */ + +package javax.imageio.event; + +import javax.imageio.ImageWriter; +import java.util.EventListener; + +/** + * The IIOWriteWarningListener provides methods to receive notification of + * warnings generated by image and thumbnail writing methods. + * + * @since Android 1.0 + */ +public interface IIOWriteWarningListener extends EventListener { + + /** + * Notifies this listener about a warning (non-fatal error) during encoding. + * + * @param source + * the ImageWriter object which calls this method. + * @param imageIndex + * the index of the image generating the warning. + * @param warning + * the string describing the warning. + */ + void warningOccurred(ImageWriter source, int imageIndex, String warning); +} diff --git a/app/src/main/java/javax/imageio/event/package.html b/app/src/main/java/javax/imageio/event/package.html new file mode 100644 index 000000000..c2fe39fae --- /dev/null +++ b/app/src/main/java/javax/imageio/event/package.html @@ -0,0 +1,8 @@ + + +

+ This package provides interfaces to handle events which can be fired during the reading or writing of images. +

+ @since Android 1.0 + + diff --git a/app/src/main/java/javax/imageio/metadata/IIOInvalidTreeException.java b/app/src/main/java/javax/imageio/metadata/IIOInvalidTreeException.java new file mode 100644 index 000000000..ba906577b --- /dev/null +++ b/app/src/main/java/javax/imageio/metadata/IIOInvalidTreeException.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.imageio.metadata; + +import org.w3c.dom.Node; +import javax.imageio.IIOException; + +/** + * The IIOInvalidTreeException provides notification about fails of + * IIOMetadataNodes tree parsing by IIOMetadata object. + * + * @since Android 1.0 + */ +public class IIOInvalidTreeException extends IIOException { + + /** + * The offending node. + */ + protected Node offendingNode = null; + + /** + * Instantiates an IIOInvalidTreeException with the specified detailed + * message and specified offending Node. + * + * @param message + * the detailed message. + * @param offendingNode + * the offending node. + */ + public IIOInvalidTreeException(String message, Node offendingNode) { + super(message); + this.offendingNode = offendingNode; + } + + /** + * Instantiates a new IIOInvalidTreeException with the specified detailed + * message and specified offending Node. + * + * @param message + * the detailed message. + * @param cause + * the cause of this exception. + * @param offendingNode + * the offending node. + */ + public IIOInvalidTreeException(String message, Throwable cause, Node offendingNode) { + super(message, cause); + this.offendingNode = offendingNode; + } + + /** + * Gets the offending node. + * + * @return the offending node. + */ + public Node getOffendingNode() { + return offendingNode; + } +} diff --git a/app/src/main/java/javax/imageio/metadata/IIOMetadata.java b/app/src/main/java/javax/imageio/metadata/IIOMetadata.java new file mode 100644 index 000000000..96cebf98d --- /dev/null +++ b/app/src/main/java/javax/imageio/metadata/IIOMetadata.java @@ -0,0 +1,391 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.imageio.metadata; + +import java.util.ArrayList; + +import org.apache.harmony.x.imageio.metadata.IIOMetadataUtils; +import org.w3c.dom.Node; + +/** + * The class IIOMetadata represents the metadata (bundled with an image) as a + * Dom-type tree. + * + * @since Android 1.0 + */ +public abstract class IIOMetadata { + + /** + * Whether the standard metadata format is supported. + */ + protected boolean standardFormatSupported; + + /** + * The native metadata format name. + */ + protected String nativeMetadataFormatName; + + /** + * The native metadata format class name. + */ + protected String nativeMetadataFormatClassName; + + /** + * The extra metadata format names. + */ + protected String[] extraMetadataFormatNames; + + /** + * The extra metadata format class names. + */ + protected String[] extraMetadataFormatClassNames; + + /** + * The default controller. + */ + protected IIOMetadataController defaultController; + + /** + * The controller. + */ + protected IIOMetadataController controller; + + /** + * Instantiates a new IIOMetadata with no data set. + */ + protected IIOMetadata() { + } + + /** + * Instantiates a new IIOMetadata with the specified data parameters. + * + * @param standardMetadataFormatSupported + * whether the standard metadata format is supported. + * @param nativeMetadataFormatName + * the native metadata format name. + * @param nativeMetadataFormatClassName + * the native metadata format class name. + * @param extraMetadataFormatNames + * the extra metadata format names. + * @param extraMetadataFormatClassNames + * the extra metadata format class names. + */ + protected IIOMetadata(boolean standardMetadataFormatSupported, String nativeMetadataFormatName, + String nativeMetadataFormatClassName, String[] extraMetadataFormatNames, + String[] extraMetadataFormatClassNames) { + standardFormatSupported = standardMetadataFormatSupported; + this.nativeMetadataFormatName = nativeMetadataFormatName; + this.nativeMetadataFormatClassName = nativeMetadataFormatClassName; + if (extraMetadataFormatNames == null) { + if (extraMetadataFormatClassNames != null) { + throw new IllegalArgumentException( + "extraMetadataFormatNames == null && extraMetadataFormatClassNames != null!"); + } + } else { + if (extraMetadataFormatClassNames == null) { + throw new IllegalArgumentException( + "extraMetadataFormatNames != null && extraMetadataFormatClassNames == null!"); + } + if (extraMetadataFormatNames.length == 0) { + throw new IllegalArgumentException("extraMetadataFormatNames.length == 0!"); + } + if (extraMetadataFormatClassNames.length != extraMetadataFormatNames.length) { + throw new IllegalArgumentException( + "extraMetadataFormatClassNames.length != extraMetadataFormatNames.length!"); + } + this.extraMetadataFormatNames = extraMetadataFormatNames.clone(); + this.extraMetadataFormatClassNames = extraMetadataFormatClassNames.clone(); + } + } + + /** + * Gets the metadata as tree-type document. + * + * @param formatName + * the format name. + * @return the node in tree format. + */ + public abstract Node getAsTree(String formatName); + + /** + * Checks if the metadata is read only. + * + * @return true, if the metadata is read only. + */ + public abstract boolean isReadOnly(); + + /** + * Merges the specified tree with this metadata tree. + * + * @param formatName + * the format of the specified tree. + * @param root + * the root node of the metadata tree. + * @throws IIOInvalidTreeException + * if the specified tree is incompatible with the this metadata + * tree. + */ + public abstract void mergeTree(String formatName, Node root) throws IIOInvalidTreeException; + + /** + * Resets the controller. + */ + public abstract void reset(); + + /** + * Gets the controller associated with this metadata document. + * + * @return the controller. + */ + public IIOMetadataController getController() { + return controller; + } + + /** + * Checks whether this metadata has a controller. + * + * @return true, if this metadata has a controller. + */ + public boolean hasController() { + return getController() != null; + } + + /** + * Activate the controller. + * + * @return true, if successful. + */ + public boolean activateController() { + if (!hasController()) { + throw new IllegalStateException("hasController() == false!"); + } + return getController().activate(this); + } + + /** + * Gets the default controller. + * + * @return the default controller. + */ + public IIOMetadataController getDefaultController() { + return defaultController; + } + + /** + * Gets the extra metadata format names. + * + * @return the extra metadata format names. + */ + public String[] getExtraMetadataFormatNames() { + return extraMetadataFormatNames == null ? null : extraMetadataFormatNames.clone(); + } + + /** + * Gets the metadata format. + * + * @param formatName + * the format name. + * @return the metadata format. + */ + public IIOMetadataFormat getMetadataFormat(String formatName) { + return IIOMetadataUtils.instantiateMetadataFormat(formatName, standardFormatSupported, + nativeMetadataFormatName, nativeMetadataFormatClassName, extraMetadataFormatNames, + extraMetadataFormatClassNames); + } + + /** + * Gets the native metadata format name. + * + * @return the native metadata format name. + */ + public String getNativeMetadataFormatName() { + return nativeMetadataFormatName; + } + + /** + * Checks if the standard metadata format is supported. + * + * @return true, if the standard metadata format is supported. + */ + public boolean isStandardMetadataFormatSupported() { + return standardFormatSupported; + } + + /** + * Gets the metadata format names. + * + * @return the metadata format names. + */ + public String[] getMetadataFormatNames() { + ArrayList res = new ArrayList(); + + String nativeMetadataFormatName = getNativeMetadataFormatName(); + boolean standardFormatSupported = isStandardMetadataFormatSupported(); + String extraMetadataFormatNames[] = getExtraMetadataFormatNames(); + + if (standardFormatSupported) { + res.add(IIOMetadataFormatImpl.standardMetadataFormatName); + } + if (nativeMetadataFormatName != null) { + res.add(nativeMetadataFormatName); + } + if (extraMetadataFormatNames != null) { + for (String extraMetadataFormatName : extraMetadataFormatNames) { + res.add(extraMetadataFormatName); + } + } + + return res.size() > 0 ? res.toArray(new String[0]) : null; + } + + /** + * Gets the standard chroma node. + * + * @return the standard chroma node. + */ + protected IIOMetadataNode getStandardChromaNode() { + return null; + } + + /** + * Gets the standard compression node. + * + * @return the standard compression node. + */ + protected IIOMetadataNode getStandardCompressionNode() { + return null; + } + + /** + * Gets the standard data node. + * + * @return the standard data node. + */ + protected IIOMetadataNode getStandardDataNode() { + return null; + } + + /** + * Gets the standard dimension node. + * + * @return the standard dimension node. + */ + protected IIOMetadataNode getStandardDimensionNode() { + return null; + } + + /** + * Gets the standard document node. + * + * @return the standard document node. + */ + protected IIOMetadataNode getStandardDocumentNode() { + return null; + } + + /** + * Gets the standard text node. + * + * @return the standard text node. + */ + protected IIOMetadataNode getStandardTextNode() { + return null; + } + + /** + * Gets the standard tile node. + * + * @return the standard tile node. + */ + protected IIOMetadataNode getStandardTileNode() { + return null; + } + + /** + * Gets the standard transparency node. + * + * @return the standard transparency node. + */ + protected IIOMetadataNode getStandardTransparencyNode() { + return null; + } + + /** + * Gets the metadata as a tree in standard format. + * + * @return the metadata as a tree in standard format. + */ + protected final IIOMetadataNode getStandardTree() { + // Create root node + IIOMetadataNode root = new IIOMetadataNode(IIOMetadataFormatImpl.standardMetadataFormatName); + + Node node; + if ((node = getStandardChromaNode()) != null) { + root.appendChild(node); + } + if ((node = getStandardCompressionNode()) != null) { + root.appendChild(node); + } + if ((node = getStandardDataNode()) != null) { + root.appendChild(node); + } + if ((node = getStandardDimensionNode()) != null) { + root.appendChild(node); + } + if ((node = getStandardDocumentNode()) != null) { + root.appendChild(node); + } + if ((node = getStandardTextNode()) != null) { + root.appendChild(node); + } + if ((node = getStandardTileNode()) != null) { + root.appendChild(node); + } + if ((node = getStandardTransparencyNode()) != null) { + root.appendChild(node); + } + + return root; + } + + /** + * Sets the controller. + * + * @param controller + * the new controller. + */ + public void setController(IIOMetadataController controller) { + this.controller = controller; + } + + /** + * Sets the from tree. + * + * @param formatName + * the name of the metatdata format of the from tree. + * @param root + * the root node of the from tree. + * @throws IIOInvalidTreeException + * if the tree or its format is not compatible with this + * metadata. + */ + public void setFromTree(String formatName, Node root) throws IIOInvalidTreeException { + reset(); + mergeTree(formatName, root); + } +} diff --git a/app/src/main/java/javax/imageio/metadata/IIOMetadataController.java b/app/src/main/java/javax/imageio/metadata/IIOMetadataController.java new file mode 100644 index 000000000..140594830 --- /dev/null +++ b/app/src/main/java/javax/imageio/metadata/IIOMetadataController.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Sergey I. Salishev + * @version $Revision: 1.2 $ + */ + +package javax.imageio.metadata; + +/* + * @author Sergey I. Salishev + * @version $Revision: 1.2 $ + */ + +/** + * The IIOMetadataController interface provides a method for implementing + * objects to activate the controller without defining how the controller + * obtains values. + * + * @since Android 1.0 + */ +public interface IIOMetadataController { + + /** + * Activates a controller. + * + * @param metadata + * the metadata to be modified. + * @return true, if the IIOMetadata has been modified, false otherwise. + */ + public boolean activate(IIOMetadata metadata); +} diff --git a/app/src/main/java/javax/imageio/metadata/IIOMetadataFormat.java b/app/src/main/java/javax/imageio/metadata/IIOMetadataFormat.java new file mode 100644 index 000000000..0e7e6979c --- /dev/null +++ b/app/src/main/java/javax/imageio/metadata/IIOMetadataFormat.java @@ -0,0 +1,404 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.imageio.metadata; + +import javax.imageio.ImageTypeSpecifier; +import java.util.Locale; + +/** + * The Interface IIOMetadataFormat is implemented by classes that describe the + * rules and allowed elements for a metadata document tree. + * + * @since Android 1.0 + */ +public interface IIOMetadataFormat { + + /** + * The CHILD_POLICY_EMPTY. + */ + int CHILD_POLICY_EMPTY = 0; + + /** + * The CHILD_POLICY_ALL. + */ + int CHILD_POLICY_ALL = 1; + + /** + * The CHILD_POLICY_SOME. + */ + int CHILD_POLICY_SOME = 2; + + /** + * The CHILD_POLICY_CHOICE. + */ + int CHILD_POLICY_CHOICE = 3; + + /** + * The CHILD_POLICY_SEQUENCE. + */ + int CHILD_POLICY_SEQUENCE = 4; + + /** + * The CHILD_POLICY_REPEAT. + */ + int CHILD_POLICY_REPEAT = 5; + + /** + * The maximum value for the child policy. + */ + int CHILD_POLICY_MAX = CHILD_POLICY_REPEAT; + + /** + * The DATATYPE_STRING. + */ + int DATATYPE_STRING = 0; + + /** + * The DATATYPE_BOOLEAN. + */ + int DATATYPE_BOOLEAN = 1; + + /** + * The DATATYPE_INTEGER. + */ + int DATATYPE_INTEGER = 2; + + /** + * The DATATYPE_FLOAT. + */ + int DATATYPE_FLOAT = 3; + + /** + * The DATATYPE_DOUBLE. + */ + int DATATYPE_DOUBLE = 4; + + /** + * The VALUE_NONE. + */ + int VALUE_NONE = 0; + + /** + * The VALUE_ARBITRARY. + */ + int VALUE_ARBITRARY = 1; + + /** + * The VALUE_RANGE. + */ + int VALUE_RANGE = 2; + + /** + * The VALUE_RANGE_MIN_INCLUSIVE_MASK. + */ + int VALUE_RANGE_MIN_INCLUSIVE_MASK = 4; + + /** + * The VALUE_RANGE_MAX_INCLUSIVE_MASK. + */ + int VALUE_RANGE_MAX_INCLUSIVE_MASK = 8; + + /** + * The VALUE_ENUMERATION. + */ + int VALUE_ENUMERATION = 16; + + /** + * The VALUE_LIST. + */ + int VALUE_LIST = 32; + + /** + * The VALUE_RANGE_MIN_INCLUSIVE. + */ + int VALUE_RANGE_MIN_INCLUSIVE = VALUE_RANGE | VALUE_RANGE_MIN_INCLUSIVE_MASK; + + /** + * The VALUE_RANGE_MAX_INCLUSIVE. + */ + int VALUE_RANGE_MAX_INCLUSIVE = VALUE_RANGE | VALUE_RANGE_MAX_INCLUSIVE_MASK; + + /** + * The VALUE_RANGE_MIN_MAX_INCLUSIVE. + */ + int VALUE_RANGE_MIN_MAX_INCLUSIVE = VALUE_RANGE | VALUE_RANGE_MIN_INCLUSIVE_MASK + | VALUE_RANGE_MAX_INCLUSIVE_MASK; + + /** + * Tells whether the specified element is allowed for the specified image + * type. + * + * @param elementName + * the element name. + * @param imageType + * the image type. + * @return true, if the specified element is allowed for the specified image + * type. + */ + boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType); + + /** + * Gets data type of the specified attribute of the specified element. + * + * @param elementName + * the element name. + * @param attrName + * the attribute name. + * @return the attribute's data type. + */ + int getAttributeDataType(String elementName, String attrName); + + /** + * Gets the default value of the specified attribute of the specified + * element. + * + * @param elementName + * the element name. + * @param attrName + * the attribute name. + * @return the attribute's default value. + */ + String getAttributeDefaultValue(String elementName, String attrName); + + /** + * Gets the user-friendly description of the attribute. + * + * @param elementName + * the element name. + * @param attrName + * the attribute name. + * @param locale + * the locale giving the desired language for the description. + * @return the attribute description. + */ + String getAttributeDescription(String elementName, String attrName, Locale locale); + + /** + * Gets the attribute enumerations. + * + * @param elementName + * the element name. + * @param attrName + * the attribute name. + * @return the attribute enumerations. + */ + String[] getAttributeEnumerations(String elementName, String attrName); + + /** + * Gets the maximum length of the attribute list. + * + * @param elementName + * the element name. + * @param attrName + * the attribute name. + * @return the maximum length of the attribute list. + */ + int getAttributeListMaxLength(String elementName, String attrName); + + /** + * Gets the minimum length of the attribute list. + * + * @param elementName + * the element name. + * @param attrName + * the attribute name. + * @return the minimum length of the attribute list. + */ + int getAttributeListMinLength(String elementName, String attrName); + + /** + * Gets the maximum value allowed for the attribute. + * + * @param elementName + * the element name. + * @param attrName + * the attribute name. + * @return the maximum value allowed for the attribute. + */ + String getAttributeMaxValue(String elementName, String attrName); + + /** + * Gets the minimum value allowed for the attribute. + * + * @param elementName + * the element name. + * @param attrName + * the attribute name. + * @return the minimum value allowed for the attribute. + */ + String getAttributeMinValue(String elementName, String attrName); + + /** + * Gets the attribute names allowed for the specified element. + * + * @param elementName + * the element name. + * @return the attribute names. + */ + String[] getAttributeNames(String elementName); + + /** + * Gets the attribute value type. + * + * @param elementName + * the element name. + * @param attrName + * the attribute name. + * @return the attribute value type. + */ + int getAttributeValueType(String elementName, String attrName); + + /** + * Checks whether the specified attribute is required for the specified + * element. + * + * @param elementName + * the element name. + * @param attrName + * the attribute name. + * @return true, if the specified attribute is required for the specified + * element. + */ + boolean isAttributeRequired(String elementName, String attrName); + + /** + * Gets the names of the possible child elements for the given element. + * + * @param elementName + * the element name. + * @return the child names. + */ + String[] getChildNames(String elementName); + + /** + * Gets the constant describing the element's child policy. + * + * @param elementName + * the element name. + * @return the child policy. + */ + int getChildPolicy(String elementName); + + /** + * Gets the user-friendly description of the element. + * + * @param elementName + * the element name. + * @param locale + * the locale giving the desired language for the description. + * @return the element description. + */ + String getElementDescription(String elementName, Locale locale); + + /** + * Gets the maximum number of children allowed for the element. + * + * @param elementName + * the element name. + * @return the maximum number of children allowed for the element. + */ + int getElementMaxChildren(String elementName); + + /** + * Gets the minimum number of children allowed for the element. + * + * @param elementName + * the element name. + * @return the minimum number of children allowed for the element. + */ + int getElementMinChildren(String elementName); + + /** + * Gets the maximum object array length allowed for the element. + * + * @param elementName + * the element name. + * @return the maximum object array length allowed for the element. + */ + int getObjectArrayMaxLength(String elementName); + + /** + * Gets the minimum object array length allowed for the element. + * + * @param elementName + * the element name. + * @return the minimum object array length allowed for the element. + */ + int getObjectArrayMinLength(String elementName); + + /** + * Gets the object class corresponding to the specified element. + * + * @param elementName + * the element name. + * @return the object class corresponding to the specified element. + */ + Class getObjectClass(String elementName); + + /** + * Gets the object default value for the element. + * + * @param elementName + * the element name. + * @return the object default value for the element. + */ + Object getObjectDefaultValue(String elementName); + + /** + * Gets the object enumerations. + * + * @param elementName + * the element name. + * @return the object enumerations. + */ + Object[] getObjectEnumerations(String elementName); + + /** + * Gets the maximum value allowed for the element's object. + * + * @param elementName + * the element name. + * @return the maximum value allowed for the element's object. + */ + Comparable getObjectMaxValue(String elementName); + + /** + * Gets the minimum value allowed for the element's object. + * + * @param elementName + * the element name. + * @return the minimum value allowed for the element's object. + */ + Comparable getObjectMinValue(String elementName); + + /** + * Gets the constant that indicates the type of the element's value. + * + * @param elementName + * the element name. + * @return the constant that indicates the type of the element's value. + */ + int getObjectValueType(String elementName); + + /** + * Gets the name of the root element. + * + * @return the name of the root element. + */ + String getRootName(); +} diff --git a/app/src/main/java/javax/imageio/metadata/IIOMetadataFormatImpl.java b/app/src/main/java/javax/imageio/metadata/IIOMetadataFormatImpl.java new file mode 100644 index 000000000..1a6e56853 --- /dev/null +++ b/app/src/main/java/javax/imageio/metadata/IIOMetadataFormatImpl.java @@ -0,0 +1,1056 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.imageio.metadata; + +import javax.imageio.ImageTypeSpecifier; +import java.util.*; +import java.security.AccessController; +import java.security.PrivilegedAction; + +/** + * The IIOMetadataFormatImpl class provides an implementation of the + * IIOMetadataFormat interface. + * + * @since Android 1.0 + */ +public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { + + /** + * The Constant standardMetadataFormatName. + */ + @SuppressWarnings( { + "ConstantDeclaredInAbstractClass" + }) + public static final String standardMetadataFormatName = "javax_imageio_1.0"; + + /** + * The standard format. + */ + @SuppressWarnings( { + "StaticNonFinalField" + }) + private static IIOMetadataFormatImpl standardFormat; + + /** + * The root name. + */ + private String rootName; + + /** + * The element hash. + */ + private HashMap elementHash = new HashMap(); + + /** + * The resource base name. + */ + private String resourceBaseName = getClass().getName() + "Resources"; + + /** + * Instantiates an IIOMetadataFormatImpl with the specified root name and + * child policy (not CHILD_POLICY_REPEAT). + * + * @param rootName + * the name of root element. + * @param childPolicy + * the child policy defined by one of the CHILD_POLICY_* + * constants (except CHILD_POLICY_REPEAT). + */ + public IIOMetadataFormatImpl(String rootName, int childPolicy) { + if (rootName == null) { + throw new IllegalArgumentException("rootName is null"); + } + if (childPolicy < CHILD_POLICY_EMPTY || childPolicy > CHILD_POLICY_MAX + || childPolicy == CHILD_POLICY_REPEAT) { + throw new IllegalArgumentException("childPolicy is not one of the predefined constants"); + } + + this.rootName = rootName; + Element root = new Element(); + root.name = rootName; + root.childPolicy = childPolicy; + elementHash.put(rootName, root); + } + + /** + * Instantiates an IIOMetadataFormatImpl with the specified root name and + * CHILD_POLICY_REPEAT child policy. + * + * @param rootName + * the name of root element. + * @param minChildren + * the minimum number of children. + * @param maxChildren + * the maximum number of children + */ + public IIOMetadataFormatImpl(String rootName, int minChildren, int maxChildren) { + if (rootName == null) { + throw new IllegalArgumentException("rootName is null"); + } + if (minChildren < 0) { + throw new IllegalArgumentException("minChildren < 0!"); + } + if (minChildren > maxChildren) { + throw new IllegalArgumentException("minChildren > maxChildren!"); + } + + this.rootName = rootName; + Element root = new Element(); + root.name = rootName; + root.minChildren = minChildren; + root.maxChildren = maxChildren; + root.childPolicy = CHILD_POLICY_REPEAT; + elementHash.put(rootName, root); + } + + @SuppressWarnings( { + "AbstractMethodOverridesAbstractMethod" + }) + public abstract boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType); + + /** + * Adds a new attribute to an existing element. + * + * @param elementName + * the name of the element to which the new attribute will be + * added. + * @param attrName + * the attribute name. + * @param dataType + * the data type of the new attribute. + * @param required + * the flag which indicates whether this attribute must be + * present. + * @param listMinLength + * the minimum legal number of list items. + * @param listMaxLength + * the the maximum legal number of list items. + */ + protected void addAttribute(String elementName, String attrName, int dataType, + boolean required, int listMinLength, int listMaxLength) { + if (attrName == null) { + throw new IllegalArgumentException("attrName == null!"); + } + if (dataType < DATATYPE_STRING || dataType > DATATYPE_DOUBLE) { + throw new IllegalArgumentException("Invalid value for dataType!"); + } + if (listMinLength < 0 || listMinLength > listMaxLength) { + throw new IllegalArgumentException("Invalid list bounds!"); + } + + Element element = findElement(elementName); + Attlist attr = new Attlist(); + attr.name = attrName; + attr.dataType = dataType; + attr.required = required; + attr.listMinLength = listMinLength; + attr.listMaxLength = listMaxLength; + attr.valueType = VALUE_LIST; + + element.attributes.put(attrName, attr); + } + + /** + * Adds a new attribute to an existing element. + * + * @param elementName + * the name of the element to which the new attribute will be + * added. + * @param attrName + * the attribute name. + * @param dataType + * the data type of the new attribute. + * @param required + * the flag which indicates whether this attribute must be + * present. + * @param defaultValue + * the default value of the attribute. + */ + protected void addAttribute(String elementName, String attrName, int dataType, + boolean required, String defaultValue) { + if (attrName == null) { + throw new IllegalArgumentException("attrName == null!"); + } + if (dataType < DATATYPE_STRING || dataType > DATATYPE_DOUBLE) { + throw new IllegalArgumentException("Invalid value for dataType!"); + } + + Element element = findElement(elementName); + Attlist attr = new Attlist(); + attr.name = attrName; + attr.dataType = dataType; + attr.required = required; + attr.defaultValue = defaultValue; + attr.valueType = VALUE_ARBITRARY; + + element.attributes.put(attrName, attr); + } + + /** + * Adds a new attribute to an existing element. + * + * @param elementName + * the name of the element to which the new attribute will be + * added. + * @param attrName + * the attribute name. + * @param dataType + * the data type of the new attribute. + * @param required + * the flag which indicates whether this attribute must be + * present. + * @param defaultValue + * the default value of the attribute. + * @param enumeratedValues + * the legal values for the attribute as a list of strings. + */ + protected void addAttribute(String elementName, String attrName, int dataType, + boolean required, String defaultValue, List enumeratedValues) { + if (attrName == null) { + throw new IllegalArgumentException("attrName == null!"); + } + if (dataType < DATATYPE_STRING || dataType > DATATYPE_DOUBLE) { + throw new IllegalArgumentException("Invalid value for dataType!"); + } + if (enumeratedValues == null || enumeratedValues.isEmpty()) { + throw new IllegalArgumentException("enumeratedValues is empty or null"); + } + + try { + for (String enumeratedValue : enumeratedValues) { + if (enumeratedValue == null) { + throw new IllegalArgumentException("enumeratedValues contains a null!"); + } + } + } catch (ClassCastException e) { + throw new IllegalArgumentException("enumeratedValues contains a non-String value!"); + } + + Element element = findElement(elementName); + Attlist attr = new Attlist(); + attr.name = attrName; + attr.dataType = dataType; + attr.required = required; + attr.defaultValue = defaultValue; + attr.enumeratedValues = enumeratedValues; + attr.valueType = VALUE_ENUMERATION; + + element.attributes.put(attrName, attr); + } + + /** + * Adds a new attribute to an existing element. + * + * @param elementName + * the name of the element to which the new attribute will be + * added. + * @param attrName + * the attribute name. + * @param dataType + * the data type of the new attribute. + * @param required + * the flag which indicates whether this attribute must be + * present. + * @param defaultValue + * the default value of attribute. + * @param minValue + * the minimum legal value of an attribute. + * @param maxValue + * the maximum legal value of an attribute. + * @param minInclusive + * the flag which indicates whether the minValue is inclusive. + * @param maxInclusive + * the flag which indicates whether the maxValue is inclusive. + */ + protected void addAttribute(String elementName, String attrName, int dataType, + boolean required, String defaultValue, String minValue, String maxValue, + boolean minInclusive, boolean maxInclusive) { + if (attrName == null) { + throw new IllegalArgumentException("attrName == null!"); + } + if (dataType < DATATYPE_STRING || dataType > DATATYPE_DOUBLE) { + throw new IllegalArgumentException("Invalid value for dataType!"); + } + + Element element = findElement(elementName); + Attlist attr = new Attlist(); + attr.name = attrName; + attr.dataType = dataType; + attr.required = required; + attr.defaultValue = defaultValue; + attr.minValue = minValue; + attr.maxValue = maxValue; + attr.minInclusive = minInclusive; + attr.maxInclusive = maxInclusive; + + attr.valueType = VALUE_RANGE; + attr.valueType |= minInclusive ? VALUE_RANGE_MIN_INCLUSIVE_MASK : 0; + attr.valueType |= maxInclusive ? VALUE_RANGE_MAX_INCLUSIVE_MASK : 0; + + element.attributes.put(attrName, attr); + } + + /** + * Adds a new attribute with boolean data type to an existing element. + * + * @param elementName + * the name of the element to which the new attribute will be + * added. + * @param attrName + * the attribute name. + * @param hasDefaultValue + * the flag which indicates whether this attribute must have a + * default value. + * @param defaultValue + * the default value. + */ + protected void addBooleanAttribute(String elementName, String attrName, + boolean hasDefaultValue, boolean defaultValue) { + String defaultVal = hasDefaultValue ? (defaultValue ? "TRUE" : "FALSE") : null; + ArrayList values = new ArrayList(2); + values.add("TRUE"); + values.add("FALSE"); + + addAttribute(elementName, attrName, DATATYPE_BOOLEAN, true, defaultVal, values); + } + + /** + * Adds an existing element to the list of child elements of the specified + * parent element. + * + * @param elementName + * the name of the element to be added. + * @param parentName + * the parent element name. + */ + protected void addChildElement(String elementName, String parentName) { + Element parent = findElement(parentName); + Element element = findElement(elementName); + parent.children.add(element.name); + } + + /** + * Adds a new element type to this IIOMetadataFormat with a child policy (if + * policy is not CHILD_POLICY_REPEAT). + * + * @param elementName + * the name of the element to be added. + * @param parentName + * the parent element name. + * @param childPolicy + * one of the CHILD_POLICY_* constants defined by + * IIOMetadataFormat. + */ + protected void addElement(String elementName, String parentName, int childPolicy) { + if (childPolicy < CHILD_POLICY_EMPTY || childPolicy > CHILD_POLICY_MAX + || childPolicy == CHILD_POLICY_REPEAT) { + throw new IllegalArgumentException("childPolicy is not one of the predefined constants"); + } + + Element parent = findElement(parentName); + Element element = new Element(); + element.name = elementName; + element.childPolicy = childPolicy; + elementHash.put(elementName, element); + parent.children.add(elementName); + } + + /** + * Adds a new element type to this IIOMetadataFormat with + * CHILD_POLICY_REPEAT and the specified minimum and maximum number of child + * elements. + * + * @param elementName + * the element name to be added. + * @param parentName + * the parent element name. + * @param minChildren + * the minimum number of child elements. + * @param maxChildren + * the maximum number of child elements. + */ + protected void addElement(String elementName, String parentName, int minChildren, + int maxChildren) { + if (minChildren < 0) { + throw new IllegalArgumentException("minChildren < 0!"); + } + if (minChildren > maxChildren) { + throw new IllegalArgumentException("minChildren > maxChildren!"); + } + + Element parent = findElement(parentName); + Element element = new Element(); + element.name = elementName; + element.childPolicy = CHILD_POLICY_REPEAT; + element.minChildren = minChildren; + element.maxChildren = maxChildren; + elementHash.put(elementName, element); + parent.children.add(elementName); + } + + /** + * Adds an Object reference with the specified class type to be stored as + * element's value. + * + * @param elementName + * the element name. + * @param classType + * the class indicates the legal types for the object's value. + * @param arrayMinLength + * the minimum legal length for the array. + * @param arrayMaxLength + * the maximum legal length for the array. + */ + protected void addObjectValue(String elementName, Class classType, int arrayMinLength, + int arrayMaxLength) { + Element element = findElement(elementName); + + ObjectValue objVal = new ObjectValue(); + objVal.classType = classType; + objVal.arrayMaxLength = arrayMaxLength; + objVal.arrayMinLength = arrayMinLength; + objVal.valueType = VALUE_LIST; + + element.objectValue = objVal; + } + + /** + * Adds an Object reference with the specified class type to be stored as an + * element's value. + * + * @param elementName + * the element name. + * @param classType + * the class indicates the legal types for the object's value. + * @param required + * a flag indicated that this object value must be present. + * @param defaultValue + * the default value, or null. + */ + protected void addObjectValue(String elementName, Class classType, boolean required, + T defaultValue) { + // note: reqired is an unused parameter + Element element = findElement(elementName); + + ObjectValue objVal = new ObjectValue(); + objVal.classType = classType; + objVal.defaultValue = defaultValue; + objVal.valueType = VALUE_ARBITRARY; + + element.objectValue = objVal; + } + + /** + * Adds an Object reference with the specified class type to be stored as + * the element's value. + * + * @param elementName + * the element name. + * @param classType + * the class indicates the legal types for the object value. + * @param required + * a flag indicated that this object value must be present. + * @param defaultValue + * the default value, or null. + * @param enumeratedValues + * the list of legal values for the object. + */ + protected void addObjectValue(String elementName, Class classType, boolean required, + T defaultValue, List enumeratedValues) { + // note: reqired is an unused parameter + if (enumeratedValues == null || enumeratedValues.isEmpty()) { + throw new IllegalArgumentException("enumeratedValues is empty or null"); + } + + try { + for (T enumeratedValue : enumeratedValues) { + if (enumeratedValue == null) { + throw new IllegalArgumentException("enumeratedValues contains a null!"); + } + } + } catch (ClassCastException e) { + throw new IllegalArgumentException( + "enumeratedValues contains a value not of class classType!"); + } + + Element element = findElement(elementName); + + ObjectValue objVal = new ObjectValue(); + objVal.classType = classType; + objVal.defaultValue = defaultValue; + objVal.enumeratedValues = enumeratedValues; + objVal.valueType = VALUE_ENUMERATION; + + element.objectValue = objVal; + } + + /** + * Adds an Object reference with the specified class type to be stored as + * the element's value. + * + * @param elementName + * the element name. + * @param classType + * the class indicates the legal types for the object value. + * @param defaultValue + * the default value, or null. + * @param minValue + * the minimum legal value for the object value. + * @param maxValue + * the maximum legal value for the object value. + * @param minInclusive + * the flag which indicates whether the minValue is inclusive. + * @param maxInclusive + * the flag which indicates whether the maxValue is inclusive. + */ + protected > void addObjectValue(String elementName, + Class classType, T defaultValue, Comparable minValue, + Comparable maxValue, boolean minInclusive, boolean maxInclusive) { + Element element = findElement(elementName); + + ObjectValue objVal = new ObjectValue(); + objVal.classType = classType; + objVal.defaultValue = defaultValue; + objVal.minValue = minValue; + objVal.maxValue = maxValue; + objVal.minInclusive = minInclusive; + objVal.maxInclusive = maxInclusive; + + objVal.valueType = VALUE_RANGE; + objVal.valueType |= minInclusive ? VALUE_RANGE_MIN_INCLUSIVE_MASK : 0; + objVal.valueType |= maxInclusive ? VALUE_RANGE_MAX_INCLUSIVE_MASK : 0; + + element.objectValue = objVal; + } + + public int getAttributeDataType(String elementName, String attrName) { + Attlist attr = findAttribute(elementName, attrName); + return attr.dataType; + } + + public String getAttributeDefaultValue(String elementName, String attrName) { + Attlist attr = findAttribute(elementName, attrName); + return attr.defaultValue; + } + + public String getAttributeDescription(String elementName, String attrName, Locale locale) { + findAttribute(elementName, attrName); + return getResourceString(elementName + "/" + attrName, locale); + } + + public String[] getAttributeEnumerations(String elementName, String attrName) { + Attlist attr = findAttribute(elementName, attrName); + if (attr.valueType != VALUE_ENUMERATION) { + throw new IllegalArgumentException("Attribute is not an enumeration!"); + } + + return attr.enumeratedValues.toArray(new String[attr.enumeratedValues.size()]); + } + + public int getAttributeListMaxLength(String elementName, String attrName) { + Attlist attr = findAttribute(elementName, attrName); + if (attr.valueType != VALUE_LIST) { + throw new IllegalArgumentException("Attribute is not a list!"); + } + return attr.listMaxLength; + } + + public int getAttributeListMinLength(String elementName, String attrName) { + Attlist attr = findAttribute(elementName, attrName); + if (attr.valueType != VALUE_LIST) { + throw new IllegalArgumentException("Attribute is not a list!"); + } + return attr.listMinLength; + } + + public String getAttributeMaxValue(String elementName, String attrName) { + Attlist attr = findAttribute(elementName, attrName); + if ((attr.valueType & VALUE_RANGE) == 0) { + throw new IllegalArgumentException("Attribute is not a range!"); + } + return attr.maxValue; + } + + public String getAttributeMinValue(String elementName, String attrName) { + Attlist attr = findAttribute(elementName, attrName); + if ((attr.valueType & VALUE_RANGE) == 0) { + throw new IllegalArgumentException("Attribute is not a range!"); + } + return attr.minValue; + } + + public String[] getAttributeNames(String elementName) { + Element element = findElement(elementName); + return element.attributes.keySet().toArray(new String[element.attributes.size()]); + } + + public int getAttributeValueType(String elementName, String attrName) { + Attlist attr = findAttribute(elementName, attrName); + return attr.valueType; + } + + public String[] getChildNames(String elementName) { + Element element = findElement(elementName); + if (element.childPolicy == CHILD_POLICY_EMPTY) { // Element cannot have + // children + return null; + } + return element.children.toArray(new String[element.children.size()]); + } + + public int getChildPolicy(String elementName) { + Element element = findElement(elementName); + return element.childPolicy; + } + + public String getElementDescription(String elementName, Locale locale) { + findElement(elementName); // Check if there is such element + return getResourceString(elementName, locale); + } + + public int getElementMaxChildren(String elementName) { + Element element = findElement(elementName); + if (element.childPolicy != CHILD_POLICY_REPEAT) { + throw new IllegalArgumentException("Child policy is not CHILD_POLICY_REPEAT!"); + } + return element.maxChildren; + } + + public int getElementMinChildren(String elementName) { + Element element = findElement(elementName); + if (element.childPolicy != CHILD_POLICY_REPEAT) { + throw new IllegalArgumentException("Child policy is not CHILD_POLICY_REPEAT!"); + } + return element.minChildren; + } + + public int getObjectArrayMaxLength(String elementName) { + Element element = findElement(elementName); + ObjectValue v = element.objectValue; + if (v == null || v.valueType != VALUE_LIST) { + throw new IllegalArgumentException("Not a list!"); + } + return v.arrayMaxLength; + } + + public int getObjectArrayMinLength(String elementName) { + Element element = findElement(elementName); + ObjectValue v = element.objectValue; + if (v == null || v.valueType != VALUE_LIST) { + throw new IllegalArgumentException("Not a list!"); + } + return v.arrayMinLength; + } + + public Class getObjectClass(String elementName) { + ObjectValue v = findObjectValue(elementName); + return v.classType; + } + + public Object getObjectDefaultValue(String elementName) { + ObjectValue v = findObjectValue(elementName); + return v.defaultValue; + } + + public Object[] getObjectEnumerations(String elementName) { + Element element = findElement(elementName); + ObjectValue v = element.objectValue; + if (v == null || v.valueType != VALUE_ENUMERATION) { + throw new IllegalArgumentException("Not an enumeration!"); + } + return v.enumeratedValues.toArray(); + } + + public Comparable getObjectMaxValue(String elementName) { + Element element = findElement(elementName); + ObjectValue v = element.objectValue; + if (v == null || (v.valueType & VALUE_RANGE) == 0) { + throw new IllegalArgumentException("Not a range!"); + } + return v.maxValue; + } + + public Comparable getObjectMinValue(String elementName) { + Element element = findElement(elementName); + ObjectValue v = element.objectValue; + if (v == null || (v.valueType & VALUE_RANGE) == 0) { + throw new IllegalArgumentException("Not a range!"); + } + return v.minValue; + } + + public int getObjectValueType(String elementName) { + Element element = findElement(elementName); + if (element.objectValue == null) { + return VALUE_NONE; + } + return element.objectValue.valueType; + } + + /** + * Gets the resource base name for locating ResourceBundles. + * + * @return the current resource base name. + */ + protected String getResourceBaseName() { + return resourceBaseName; + } + + public String getRootName() { + return rootName; + } + + /** + * Gets the standard format instance. + * + * @return the IIOMetadataFormat instance. + */ + public static IIOMetadataFormat getStandardFormatInstance() { + if (standardFormat == null) { + standardFormat = new IIOStandardMetadataFormat(); + } + + return standardFormat; + } + + public boolean isAttributeRequired(String elementName, String attrName) { + return findAttribute(elementName, attrName).required; + } + + /** + * Removes the specified attribute from the specified element. + * + * @param elementName + * the specified element name. + * @param attrName + * the specified attribute name. + */ + protected void removeAttribute(String elementName, String attrName) { + Element element = findElement(elementName); + element.attributes.remove(attrName); + } + + /** + * Removes the specified element from this format. + * + * @param elementName + * the specified element name. + */ + protected void removeElement(String elementName) { + Element element; + if ((element = elementHash.get(elementName)) != null) { + elementHash.remove(elementName); + for (Element e : elementHash.values()) { + e.children.remove(element.name); + } + } + } + + /** + * Removes the object value from the specified element. + * + * @param elementName + * the element name. + */ + protected void removeObjectValue(String elementName) { + Element element = findElement(elementName); + element.objectValue = null; + } + + /** + * Sets a new base name for ResourceBundles containing descriptions of + * elements and attributes for this format. + * + * @param resourceBaseName + * the new resource base name. + */ + protected void setResourceBaseName(String resourceBaseName) { + if (resourceBaseName == null) { + throw new IllegalArgumentException("resourceBaseName == null!"); + } + this.resourceBaseName = resourceBaseName; + } + + /** + * The Class Element. + */ + @SuppressWarnings( { + "ClassWithoutConstructor" + }) + private class Element { + + /** + * The name. + */ + String name; + + /** + * The children. + */ + ArrayList children = new ArrayList(); + + /** + * The attributes. + */ + HashMap attributes = new HashMap(); + + /** + * The min children. + */ + int minChildren; + + /** + * The max children. + */ + int maxChildren; + + /** + * The child policy. + */ + int childPolicy; + + /** + * The object value. + */ + ObjectValue objectValue; + } + + /** + * The Class Attlist. + */ + @SuppressWarnings( { + "ClassWithoutConstructor" + }) + private class Attlist { + + /** + * The name. + */ + String name; + + /** + * The data type. + */ + int dataType; + + /** + * The required. + */ + boolean required; + + /** + * The list min length. + */ + int listMinLength; + + /** + * The list max length. + */ + int listMaxLength; + + /** + * The default value. + */ + String defaultValue; + + /** + * The enumerated values. + */ + List enumeratedValues; + + /** + * The min value. + */ + String minValue; + + /** + * The max value. + */ + String maxValue; + + /** + * The min inclusive. + */ + boolean minInclusive; + + /** + * The max inclusive. + */ + boolean maxInclusive; + + /** + * The value type. + */ + int valueType; + } + + /** + * The Class ObjectValue. + */ + @SuppressWarnings( { + "ClassWithoutConstructor" + }) + private class ObjectValue { + + /** + * The class type. + */ + Class classType; + + /** + * The array min length. + */ + int arrayMinLength; + + /** + * The array max length. + */ + int arrayMaxLength; + + /** + * The default value. + */ + T defaultValue; + + /** + * The enumerated values. + */ + List enumeratedValues; + + /** + * The min value. + */ + Comparable minValue; + + /** + * The max value. + */ + Comparable maxValue; + + /** + * The min inclusive. + */ + boolean minInclusive; + + /** + * The max inclusive. + */ + boolean maxInclusive; + + /** + * The value type. + */ + int valueType; + } + + /** + * Find element. + * + * @param name + * the name. + * @return the element. + */ + private Element findElement(String name) { + Element element; + if ((element = elementHash.get(name)) == null) { + throw new IllegalArgumentException("element name is null or no such element: " + name); + } + + return element; + } + + /** + * Find attribute. + * + * @param elementName + * the element name. + * @param attributeName + * the attribute name. + * @return the attlist. + */ + private Attlist findAttribute(String elementName, String attributeName) { + Element element = findElement(elementName); + Attlist attribute; + if ((attribute = element.attributes.get(attributeName)) == null) { + throw new IllegalArgumentException("attribute name is null or no such attribute: " + + attributeName); + } + + return attribute; + } + + /** + * Find object value. + * + * @param elementName + * the element name. + * @return the object value. + */ + private ObjectValue findObjectValue(String elementName) { + Element element = findElement(elementName); + ObjectValue v = element.objectValue; + if (v == null) { + throw new IllegalArgumentException("No object within element"); + } + return v; + } + + /** + * Gets the resource string. + * + * @param key + * the key. + * @param locale + * the locale. + * @return the resource string. + */ + private String getResourceString(String key, Locale locale) { + if (locale == null) { + locale = Locale.getDefault(); + } + + // Get the context class loader and try to locate the bundle with it + // first + ClassLoader contextClassloader = AccessController + .doPrivileged(new PrivilegedAction() { + public ClassLoader run() { + return Thread.currentThread().getContextClassLoader(); + } + }); + + // Now try to get the resource bundle + ResourceBundle rb; + try { + rb = ResourceBundle.getBundle(resourceBaseName, locale, contextClassloader); + } catch (MissingResourceException e) { + try { + rb = ResourceBundle.getBundle(resourceBaseName, locale); + } catch (MissingResourceException e1) { + return null; + } + } + + try { + return rb.getString(key); + } catch (MissingResourceException e) { + return null; + } catch (ClassCastException e) { + return null; // Not a string resource + } + } +} diff --git a/app/src/main/java/javax/imageio/metadata/IIOMetadataNode.java b/app/src/main/java/javax/imageio/metadata/IIOMetadataNode.java new file mode 100644 index 000000000..efbaae87b --- /dev/null +++ b/app/src/main/java/javax/imageio/metadata/IIOMetadataNode.java @@ -0,0 +1,1080 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.imageio.metadata; + +import java.util.ArrayList; +import java.util.List; + +import org.w3c.dom.Attr; +import org.w3c.dom.DOMException; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.TypeInfo; +import org.w3c.dom.UserDataHandler; + +//???AWT +//import org.w3c.dom.TypeInfo; +//import org.w3c.dom.UserDataHandler; + +/** + * The Class IIOMetadataNode represents a node of the (DOM-style) metadata tree. + * + * @since Android 1.0 + */ +public class IIOMetadataNode implements Element, NodeList { + + /** + * The node name. + */ + private String nodeName; + + /** + * The node value. + */ + private String nodeValue; + + /** + * The attributes. + */ + private IIOMetadataNodeList attrs = new IIOMetadataNodeList(new ArrayList()); + + /** + * The parent node. + */ + private IIOMetadataNode parent; + + /** + * The first child node. + */ + private IIOMetadataNode firstChild; + + /** + * The last child node. + */ + private IIOMetadataNode lastChild; + + /** + * The previous sibling. + */ + private IIOMetadataNode previousSibling; + + /** + * The next sibling. + */ + private IIOMetadataNode nextSibling; + + /** + * The number of children. + */ + private int nChildren; + + /** + * The user object associated with this node. + */ + private Object userObject; + + /** + * The text content of this node. + */ + private String textContent; + + /** + * Instantiates a new empty node. + */ + public IIOMetadataNode() { + } + + /** + * Instantiates a new empty node with the specified name. + * + * @param nodeName + * the node name. + */ + public IIOMetadataNode(String nodeName) { + this.nodeName = nodeName; + } + + /** + * Instantiates a new IIOMetadataNode with the specified name and value. + * + * @param nodeName + * the node name. + * @param nodeValue + * the node value. + */ + private IIOMetadataNode(String nodeName, String nodeValue) { + this.nodeName = nodeName; + this.nodeValue = nodeValue; + } + + public String getTagName() { + return nodeName; + } + + public String getAttribute(String name) { + Attr attrNode = (Attr)attrs.getNamedItem(name); + return (attrNode == null) ? "" : attrNode.getValue(); + } + + public void setAttribute(String name, String value) throws DOMException { + Attr attr = (Attr)attrs.getNamedItem(name); + if (attr != null) { + attr.setValue(value); + } else { + attrs.list.add(new IIOMetadataAttr(name, value, this)); + } + } + + public void removeAttribute(String name) throws DOMException { + IIOMetadataAttr attr = (IIOMetadataAttr)attrs.getNamedItem(name); + if (attr != null) { + attr.setOwnerElement(null); + attrs.list.remove(attr); + } + } + + public Attr getAttributeNode(String name) { + return (Attr)attrs.getNamedItem(name); + } + + public Attr setAttributeNode(Attr newAttr) throws DOMException { + // Check if this attribute is already in use. + Element owner = newAttr.getOwnerElement(); + if (owner != null) { + if (owner == this) { // Replacing an attribute node by itself has no + // effect + return null; + } else { + throw new DOMException(DOMException.INUSE_ATTRIBUTE_ERR, + "Attribute is already in use"); + } + } + + String name = newAttr.getName(); + Attr oldAttr = getAttributeNode(name); + if (oldAttr != null) { + removeAttributeNode(oldAttr); + } + + IIOMetadataAttr iioAttr; + if (newAttr instanceof IIOMetadataAttr) { + iioAttr = (IIOMetadataAttr)newAttr; + iioAttr.setOwnerElement(this); + } else { + iioAttr = new IIOMetadataAttr(name, newAttr.getValue(), this); + } + + attrs.list.add(iioAttr); + + return oldAttr; + } + + public Attr removeAttributeNode(Attr oldAttr) throws DOMException { + if (!attrs.list.remove(oldAttr)) { // Not found + throw new DOMException(DOMException.NOT_FOUND_ERR, "No such attribute!"); + } + + ((IIOMetadataAttr)oldAttr).setOwnerElement(null); + + return oldAttr; + } + + public NodeList getElementsByTagName(String name) { + ArrayList nodes = new ArrayList(); + + // Non-recursive tree walk + Node pos = this; + + while (pos != null) { + if (pos.getNodeName().equals(name)) { + nodes.add((IIOMetadataNode)pos); + } + + Node nextNode = pos.getFirstChild(); + + while (nextNode == null) { + if (pos == this) { + break; + } + + nextNode = pos.getNextSibling(); + + if (nextNode == null) { + pos = pos.getParentNode(); + + if (pos == null || pos == this) { + nextNode = null; + break; + } + } + } + pos = nextNode; + } + + return new IIOMetadataNodeList(nodes); + } + + public String getAttributeNS(String namespaceURI, String localName) throws DOMException { + return getAttribute(localName); + } + + public void setAttributeNS(String namespaceURI, String qualifiedName, String value) + throws DOMException { + setAttribute(qualifiedName, value); + } + + public void removeAttributeNS(String namespaceURI, String localName) throws DOMException { + removeAttribute(localName); + } + + public Attr getAttributeNodeNS(String namespaceURI, String localName) throws DOMException { + return getAttributeNode(localName); + } + + public Attr setAttributeNodeNS(Attr newAttr) throws DOMException { + return setAttributeNode(newAttr); + } + + public NodeList getElementsByTagNameNS(String namespaceURI, String localName) + throws DOMException { + return getElementsByTagName(localName); + } + + public boolean hasAttribute(String name) { + return attrs.getNamedItem(name) != null; + } + + public boolean hasAttributeNS(String namespaceURI, String localName) throws DOMException { + return hasAttribute(localName); + } + + // ???AWT + /* + * public TypeInfo getSchemaTypeInfo() { throw new + * DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); } + */ + + /** + * Description copied from interface: org.w3c.dom.Element (DOM Level + * 3) + *

+ * If the parameter isId is true, this method declares the specified + * attribute to be a user-determined ID attribute . This affects the value + * of Attr.isId and the behavior of Document.getElementById, but does not + * change any schema that may be in use, in particular this does not affect + * the Attr.schemaTypeInfo of the specified Attr node. Use the value false + * for the parameter isId to undeclare an attribute for being a + * user-determined ID attribute. To specify an attribute by local name and + * namespace URI, use the setIdAttributeNS method. + *

+ * + * @param name + * the name of the attribute. + * @param isId + * the flag which determines whether this attribute is of type + * ID. + * @throws DOMException + * if a DOM error occurred while setting the attribute type. + *

+ * NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly. + *
+ * NOT_FOUND_ERR: Raised if the specified node is not an + * attribute of this element. + *

+ */ + public void setIdAttribute(String name, boolean isId) throws DOMException { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + /** + * Description copied from interface: org.w3c.dom.Element (DOM Level + * 3) + *

+ * If the parameter isId is true, this method declares the specified + * attribute to be a user-determined ID attribute . This affects the value + * of Attr.isId and the behavior of Document.getElementById, but does not + * change any schema that may be in use, in particular this does not affect + * the Attr.schemaTypeInfo of the specified Attr node. Use the value false + * for the parameter isId to undeclare an attribute for being a + * user-determined ID attribute. + *

+ * + * @param namespaceURI + * the namespace URI of the attribute. + * @param localName + * the local name of the attribute. + * @param isId + * the flag which determines whether this attribute is of type + * ID. + * @throws DOMException + * if a DOM error occurred while setting the attribute type. + *

+ * NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly. + *
+ * NOT_FOUND_ERR: Raised if the specified node is not an + * attribute of this element. + *

+ */ + public void setIdAttributeNS(String namespaceURI, String localName, boolean isId) + throws DOMException { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + /** + * Description copied from interface: org.w3c.dom.Element (DOM Level + * 3) + *

+ * If the parameter isId is true, this method declares the specified + * attribute to be a user-determined ID attribute . This affects the value + * of Attr.isId and the behavior of Document.getElementById, but does not + * change any schema that may be in use, in particular this does not affect + * the Attr.schemaTypeInfo of the specified Attr node. Use the value false + * for the parameter isId to undeclare an attribute for being a + * user-determined ID attribute. + *

+ * + * @param idAttr + * the attribute node. + * @param isId + * the flag which determines whether this attribute is of type + * ID. + * @throws DOMException + * if a DOM error occurred while setting the attribute type. + *

+ * NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly. + *
+ * NOT_FOUND_ERR: Raised if the specified node is not an + * attribute of this element. + *

+ */ + public void setIdAttributeNode(Attr idAttr, boolean isId) throws DOMException { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + public String getNodeName() { + return nodeName; + } + + public String getNodeValue() throws DOMException { + return nodeValue; + } + + public void setNodeValue(String nodeValue) throws DOMException { + this.nodeValue = nodeValue; + } + + public short getNodeType() { + return ELEMENT_NODE; + } + + public Node getParentNode() { + return parent; + } + + public NodeList getChildNodes() { + return this; + } + + public Node getFirstChild() { + return firstChild; + } + + public Node getLastChild() { + return lastChild; + } + + public Node getPreviousSibling() { + return previousSibling; + } + + public Node getNextSibling() { + return nextSibling; + } + + public NamedNodeMap getAttributes() { + return attrs; + } + + public Document getOwnerDocument() { + return null; + } + + public Node insertBefore(Node newChild, Node refChild) throws DOMException { + if (newChild == null) { + throw new IllegalArgumentException("newChild == null!"); + } + + IIOMetadataNode newIIOChild = (IIOMetadataNode)newChild; + IIOMetadataNode refIIOChild = (IIOMetadataNode)refChild; + + newIIOChild.parent = this; + + if (refIIOChild == null) { + newIIOChild.nextSibling = null; + newIIOChild.previousSibling = lastChild; + + // Fix this node + lastChild = newIIOChild; + if (firstChild == null) { + firstChild = newIIOChild; + } + } else { + newIIOChild.nextSibling = refIIOChild; + newIIOChild.previousSibling = refIIOChild.previousSibling; + + // Fix this node + if (firstChild == refIIOChild) { + firstChild = newIIOChild; + } + + // Fix next node + if (refIIOChild != null) { + refIIOChild.previousSibling = newIIOChild; + } + } + + // Fix prev node + if (newIIOChild.previousSibling != null) { + newIIOChild.previousSibling.nextSibling = newIIOChild; + } + + nChildren++; + + return newIIOChild; + } + + public Node replaceChild(Node newChild, Node oldChild) throws DOMException { + if (newChild == null) { + throw new IllegalArgumentException("newChild == null!"); + } + + IIOMetadataNode newIIOChild = (IIOMetadataNode)newChild; + IIOMetadataNode oldIIOChild = (IIOMetadataNode)oldChild; + + IIOMetadataNode next = oldIIOChild.nextSibling; + IIOMetadataNode previous = oldIIOChild.previousSibling; + + // Fix new node + newIIOChild.parent = this; + newIIOChild.nextSibling = next; + newIIOChild.previousSibling = previous; + + // Fix this node + if (lastChild == oldIIOChild) { + lastChild = newIIOChild; + } + if (firstChild == oldIIOChild) { + firstChild = newIIOChild; + } + + // Fix siblings + if (next != null) { + next.previousSibling = newIIOChild; + } + if (previous != null) { + previous.nextSibling = newIIOChild; + } + + // Fix old child + oldIIOChild.parent = null; + oldIIOChild.nextSibling = next; + oldIIOChild.previousSibling = previous; + + return oldIIOChild; + } + + public Node removeChild(Node oldChild) throws DOMException { + if (oldChild == null) { + throw new IllegalArgumentException("oldChild == null!"); + } + + IIOMetadataNode oldIIOChild = (IIOMetadataNode)oldChild; + + // Fix next and previous + IIOMetadataNode previous = oldIIOChild.previousSibling; + IIOMetadataNode next = oldIIOChild.nextSibling; + + if (previous != null) { + previous.nextSibling = next; + } + if (next != null) { + next.previousSibling = previous; + } + + // Fix this node + if (lastChild == oldIIOChild) { + lastChild = previous; + } + if (firstChild == oldIIOChild) { + firstChild = next; + } + nChildren--; + + // Fix old child + oldIIOChild.parent = null; + oldIIOChild.previousSibling = null; + oldIIOChild.nextSibling = null; + + return oldIIOChild; + } + + public Node appendChild(Node newChild) throws DOMException { + return insertBefore(newChild, null); + } + + public boolean hasChildNodes() { + return nChildren != 0; + } + + public Node cloneNode(boolean deep) { + IIOMetadataNode cloned = new IIOMetadataNode(nodeName); + cloned.setUserObject(getUserObject()); + + if (deep) { // Clone recursively + IIOMetadataNode c = firstChild; + while (c != null) { + cloned.insertBefore(c.cloneNode(true), null); + c = c.nextSibling; + } + } + + return cloned; // To change body of implemented methods use File | + // Settings | File Templates. + } + + public void normalize() { + // Do nothing + } + + public boolean isSupported(String feature, String version) { + return false; + } + + public String getNamespaceURI() { + return null; + } + + public String getPrefix() { + return null; + } + + public void setPrefix(String prefix) throws DOMException { + // Do nothing + } + + public String getLocalName() { + return nodeName; + } + + public boolean hasAttributes() { + return attrs.list.size() > 0; + } + + /** + * Description copied from interface: org.w3c.dom.Node (DOM Level 3) + *

+ * The absolute base URI of this node or null if the implementation wasn't + * able to obtain an absolute URI. This value is computed as described in. + * However, when the Document supports the feature "HTML" [DOM Level 2 + * HTML], the base URI is computed using first the value of the href + * attribute of the HTML BASE element if any, and the value of the + * documentURI attribute from the Document interface otherwise. + *

+ * + * @return the string representation of the absolute base URI. + */ + public String getBaseURI() { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + /** + * Description copied from interface: org.w3c.dom.Node (DOM Level 3) + *

+ * Compares the reference node, i.e. the node on which this method is being + * called, with a node, i.e. the one passed as a parameter, with regard to + * their position in the document and according to the document order. + *

+ * + * @param other + * the node to compare against the reference node. + * @return Returns how the node is positioned relatively to the reference + * node. + * @throws DOMException + * NOT_SUPPORTED_ERR: when the compared nodes are from different + * DOM implementations that do not coordinate to return + * consistent implementation-specific results. + */ + public short compareDocumentPosition(Node other) throws DOMException { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + /** + * Description copied from interface: org.w3c.dom.Node (DOM Level 3) + *

+ * This attribute returns the text content of this node and its descendants. + * When it is defined to be null, setting it has no effect. On setting, any + * possible children this node may have are removed and, if it the new + * string is not empty or null, replaced by a single Text node containing + * the string this attribute is set to. On getting, no serialization is + * performed, the returned string does not contain any markup. No whitespace + * normalization is performed and the returned string does not contain the + * white spaces in element content (see the attribute + * Text.isElementContentWhitespace). Similarly, on setting, no parsing is + * performed either, the input string is taken as pure textual content. The + * string returned is made of the text content of this node depending on its + * type, as defined below: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Node typeContent
ELEMENT_NODE, ATTRIBUTE_NODE, ENTITY_NODE, ENTITY_REFERENCE_NODE, + * DOCUMENT_FRAGMENT_NODEconcatenation of the textContent attribute value of every child node, + * excluding COMMENT_NODE and PROCESSING_INSTRUCTION_NODE nodes. This is the + * empty string if the node has no children.
TEXT_NODE, CDATA_SECTION_NODE, COMMENT_NODE, + * PROCESSING_INSTRUCTION_NODEnodeValue
DOCUMENT_NODE, DOCUMENT_TYPE_NODE, NOTATION_NODEnull
+ *

+ * + * @return the text content depending on the type of this node. + * @throws DOMException + * DOMSTRING_SIZE_ERR: Raised when it would return more + * characters than fit in a DOMString variable on the + * implementation platform. + */ + public String getTextContent() throws DOMException { + return textContent; + } + + /** + * Description copied from interface: org.w3c.dom.Node (DOM Level 3) + *

+ * This attribute returns the text content of this node and its descendants. + * When it is defined to be null, setting it has no effect. On setting, any + * possible children this node may have are removed and, if it the new + * string is not empty or null, replaced by a single Text node containing + * the string this attribute is set to. On getting, no serialization is + * performed, the returned string does not contain any markup. No whitespace + * normalization is performed and the returned string does not contain the + * white spaces in element content (see the attribute + * Text.isElementContentWhitespace). Similarly, on setting, no parsing is + * performed either, the input string is taken as pure textual content. The + * string returned is made of the text content of this node depending on its + * type, as defined below: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Node typeContent
ELEMENT_NODE, ATTRIBUTE_NODE, ENTITY_NODE, ENTITY_REFERENCE_NODE, + * DOCUMENT_FRAGMENT_NODEconcatenation of the textContent attribute value of every child node, + * excluding COMMENT_NODE and PROCESSING_INSTRUCTION_NODE nodes. This is the + * empty string if the node has no children.
TEXT_NODE, CDATA_SECTION_NODE, COMMENT_NODE, + * PROCESSING_INSTRUCTION_NODEnodeValue
DOCUMENT_NODE, DOCUMENT_TYPE_NODE, NOTATION_NODEnull
+ *

+ * + * @param textContent + * the text content for this node. + * @throws DOMException + * NO_MODIFICATION_ALLOWED_ERR: Raised when the node is + * readonly. + */ + public void setTextContent(String textContent) throws DOMException { + this.textContent = textContent; + } + + /** + * Description copied from interface: org.w3c.dom.Node (DOM Level 3) + *

+ * Returns whether this node is the same node as the given one. This method + * provides a way to determine whether two Node references returned by the + * implementation reference the same object. When two Node references are + * references to the same object, even if through a proxy, the references + * may be used completely interchangeably, such that all attributes have the + * same values and calling the same DOM method on either reference always + * has exactly the same effect. + *

+ * + * @param other + * the node to test against. + * @return true, if the nodes are the same, false otherwise. + */ + public boolean isSameNode(Node other) { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + /** + * Description copied from interface: org.w3c.dom.Node (DOM Level 3) + *

+ * Look up the prefix associated to the given namespace URI, starting from + * this node. The default namespace declarations are ignored by this method. + * See for details on the algorithm used by this method. + *

+ * + * @param namespaceURI + * the namespace URI to look for. + * @return the associated namespace prefix if found or null if none is + * found. If more than one prefix are associated to the namespace + * prefix, the returned namespace prefix is implementation + * dependent. + */ + public String lookupPrefix(String namespaceURI) { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + /** + * Description copied from interface: org.w3c.dom.Node (DOM Level 3) + *

+ * This method checks if the specified namespaceURI is the default namespace + * or not. + *

+ * + * @param namespaceURI + * the namespace URI to look for. + * @return true, if the specified namespaceURI is the default namespace, + * false otherwise. + */ + public boolean isDefaultNamespace(String namespaceURI) { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + /** + * Description copied from interface: org.w3c.dom.Node (DOM Level 3) + *

+ * Look up the namespace URI associated to the given prefix, starting from + * this node. See for details on the algorithm used by this method. + *

+ * + * @param prefix + * the prefix to look for. If this parameter is null, the method + * will return the default namespace URI if any. + * @return the associated namespace URI or null if none is found. + */ + public String lookupNamespaceURI(String prefix) { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + /** + * Description copied from interface: org.w3c.dom.Node (DOM Level 3) + *

+ * Tests whether two nodes are equal. This method tests for equality of + * nodes, not sameness (i.e., whether the two nodes are references to the + * same object) which can be tested with Node.isSameNode(). All nodes that + * are the same will also be equal, though the reverse may not be true. Two + * nodes are equal if and only if the following conditions are satisfied: + *

+ *

  • The two nodes are of the same type.
  • + *
  • The following string attributes are equal: nodeName, localName, + * namespaceURI, prefix, nodeValue . This is: they are both null, or they + * have the same length and are character for character identical.
  • + *
  • The attributes NamedNodeMaps are equal. This is: they are both null, + * or they have the same length and for each node that exists in one map + * there is a node that exists in the other map and is equal, although not + * necessarily at the same index.
  • + *
  • The childNodes NodeLists are equal. This is: they are both null, or + * they have the same length and contain equal nodes at the same index. Note + * that normalization can affect equality; to avoid this, nodes should be + * normalized before being compared.
  • + *

    + * For two DocumentType nodes to be equal, the following conditions must + * also be satisfied: + *

    + *

  • The following string attributes are equal: publicId, systemId, + * internalSubset.
  • + *
  • The entities NamedNodeMaps are equal.
  • + *
  • The notations NamedNodeMaps are equal.
  • + *

    + * On the other hand, the following do not affect equality: the + * ownerDocument, baseURI, and parentNode attributes, the specified + * attribute for Attr nodes, the schemaTypeInfo attribute for Attr and + * Element nodes, the Text.isElementContentWhitespace attribute for Text + * nodes, as well as any user data or event listeners registered on the + * nodes.

    + *

    + * Note: As a general rule, anything not mentioned in the description above + * is not significant in consideration of equality checking. Note that + * future versions of this specification may take into account more + * attributes and implementations conform to this specification are expected + * to be updated accordingly. + *

    + * + * @param arg + * the node to compare equality with. + * @return true, if the nodes are equal, false otherwise. + */ + public boolean isEqualNode(Node arg) { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + /** + * Description copied from interface: org.w3c.dom.Node (DOM Level 3) + *

    + * This method returns a specialized object which implements the specialized + * APIs of the specified feature and version, as specified in. The + * specialized object may also be obtained by using binding-specific casting + * methods but is not necessarily expected to, as discussed in. This method + * also allow the implementation to provide specialized objects which do not + * support the Node interface. + *

    + * + * @param feature + * the name of the feature requested. Note that any plus sign "+" + * prepended to the name of the feature will be ignored since it + * is not significant in the context of this method. + * @param version + * this is the version number of the feature to test. + * @return the object which implements the specialized APIs of the specified + * feature and version, if any, or null if there is no object which + * implements interfaces associated with that feature. If the + * DOMObject returned by this method implements the Node interface, + * it must delegate to the primary core Node and not return results + * inconsistent with the primary core Node such as attributes, + * childNodes, etc. + */ + public Object getFeature(String feature, String version) { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + // ???AWT + /* + * public Object setUserData(String key, Object data, UserDataHandler + * handler) { throw new DOMException(DOMException.NOT_SUPPORTED_ERR, + * "Method not supported"); } + */ + + /** + * Description copied from interface: org.w3c.dom.Node (DOM Level 3) + *

    + * Retrieves the object associated to a key on a this node. The object must + * first have been set to this node by calling setUserData with the same + * key. + *

    + * + * @param key + * the key the object is associated to. + * @return the DOMUserData associated to the given key on this node, or null + * if there was none. + */ + public Object getUserData(String key) { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + public Node item(int index) { + if (index < 0 || index >= nChildren) { + return null; + } + + Node n; + for (n = getFirstChild(); index > 0; index--) { + n = n.getNextSibling(); + } + + return n; + } + + public int getLength() { + return nChildren; + } + + /** + * Gets the user object associated with this node. + * + * @return the user object associated with this node. + */ + public Object getUserObject() { + return userObject; + } + + public TypeInfo getSchemaTypeInfo() { + throw new UnsupportedOperationException(); + } + + public Object setUserData(String key, Object data, UserDataHandler handler) { + throw new UnsupportedOperationException(); + } + + /** + * Sets the user object associated with this node. + * + * @param userObject + * the new user object associated with this node. + */ + public void setUserObject(Object userObject) { + this.userObject = userObject; + } + + /** + * The Class IIOMetadataAttr. + */ + private class IIOMetadataAttr extends IIOMetadataNode implements Attr { + + /** + * The owner element. + */ + private Element ownerElement; + + /** + * Instantiates a new iIO metadata attr. + * + * @param name + * the name. + * @param value + * the value. + * @param owner + * the owner. + */ + public IIOMetadataAttr(String name, String value, Element owner) { + super(name, value); + this.ownerElement = owner; + } + + public String getName() { + return getNodeName(); + } + + public boolean getSpecified() { + return true; + } + + public String getValue() { + return nodeValue; + } + + public void setValue(String value) throws DOMException { + nodeValue = value; + } + + public Element getOwnerElement() { + return ownerElement; + } + + /** + * Sets the owner element. + * + * @param ownerElement + * the new owner element. + */ + public void setOwnerElement(Element ownerElement) { + this.ownerElement = ownerElement; + } + + /** + * @return + */ + public boolean isId() { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Method not supported"); + } + + @Override + public short getNodeType() { + return ATTRIBUTE_NODE; + } + } + + /** + * The Class IIOMetadataNodeList. + */ + private class IIOMetadataNodeList implements NodeList, NamedNodeMap { + + /** + * The list. + */ + private List list; + + /** + * Instantiates a new iIO metadata node list. + * + * @param list + * the list. + */ + IIOMetadataNodeList(List list) { + this.list = list; + } + + public Node item(int index) { + try { + return list.get(index); + } catch (IndexOutOfBoundsException e) { + return null; + } + } + + public int getLength() { + return list.size(); + } + + public Node getNamedItem(String name) { + for (IIOMetadataNode node : list) { + if (name.equals(node.getNodeName())) { + return node; + } + } + return null; + } + + public Node setNamedItem(Node arg) throws DOMException { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, + "This NamedNodeMap is read-only!"); + } + + public Node removeNamedItem(String name) throws DOMException { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, + "This NamedNodeMap is read-only!"); + } + + public Node getNamedItemNS(String namespaceURI, String localName) throws DOMException { + return getNamedItem(localName); + } + + public Node setNamedItemNS(Node arg) throws DOMException { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, + "This NamedNodeMap is read-only!"); + } + + public Node removeNamedItemNS(String namespaceURI, String localName) throws DOMException { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, + "This NamedNodeMap is read-only!"); + } + } +} diff --git a/app/src/main/java/javax/imageio/metadata/IIOStandardMetadataFormat.java b/app/src/main/java/javax/imageio/metadata/IIOStandardMetadataFormat.java new file mode 100644 index 000000000..706cb2f7a --- /dev/null +++ b/app/src/main/java/javax/imageio/metadata/IIOStandardMetadataFormat.java @@ -0,0 +1,297 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.imageio.metadata; + +import javax.imageio.ImageTypeSpecifier; +import java.util.ArrayList; + +/** + * The class IIOStandardMetadataFormat describes the rules of the standard + * metadata format. + * + * @since Android 1.0 + */ +class IIOStandardMetadataFormat extends IIOMetadataFormatImpl { + + /** + * Instantiates a new IIOStandardMetadataFormat. + */ + public IIOStandardMetadataFormat() { + super(standardMetadataFormatName, CHILD_POLICY_SOME); + buildDTD(); + } + + @Override + public boolean canNodeAppear(String elementName, ImageTypeSpecifier imageType) { + return true; + } + + /** + * Builds the DTD that describes the standard metadata format. + */ + private void buildDTD() { + // CHROMA + addElement("Chroma", standardMetadataFormatName, CHILD_POLICY_SOME); + + addElement("ColorSpaceType", "Chroma", CHILD_POLICY_EMPTY); + + ArrayList values = new ArrayList(27); + values.add("XYZ"); + values.add("Lab"); + values.add("Luv"); + values.add("YCbCr"); + values.add("Yxy"); + values.add("YCCK"); + values.add("PhotoYCC"); + values.add("RGB"); + values.add("GRAY"); + values.add("HSV"); + values.add("HLS"); + values.add("CMYK"); + values.add("CMY"); + values.add("2CLR"); + values.add("3CLR"); + values.add("4CLR"); + values.add("5CLR"); + values.add("6CLR"); + values.add("7CLR"); + values.add("8CLR"); + values.add("9CLR"); + values.add("ACLR"); + values.add("BCLR"); + values.add("CCLR"); + values.add("DCLR"); + values.add("ECLR"); + values.add("FCLR"); + addAttribute("ColorSpaceType", "name", DATATYPE_STRING, true, null, values); + + addElement("NumChannels", "Chroma", CHILD_POLICY_EMPTY); + addAttribute("NumChannels", "value", DATATYPE_INTEGER, true, 0, Integer.MAX_VALUE); // list + // - + // why + // ? + + addElement("Gamma", "Chroma", CHILD_POLICY_EMPTY); + addAttribute("Gamma", "value", DATATYPE_FLOAT, true, null); + + addElement("BlackIsZero", "Chroma", CHILD_POLICY_EMPTY); + addBooleanAttribute("BlackIsZero", "value", true, true); + + addElement("Palette", "Chroma", 0, Integer.MAX_VALUE); // CHILD_POLICY_REPEAT + addElement("PaletteEntry", "Palette", CHILD_POLICY_EMPTY); + addAttribute("PaletteEntry", "index", DATATYPE_INTEGER, true, null); + addAttribute("PaletteEntry", "red", DATATYPE_INTEGER, true, null); + addAttribute("PaletteEntry", "green", DATATYPE_INTEGER, true, null); + addAttribute("PaletteEntry", "blue", DATATYPE_INTEGER, true, null); + addAttribute("PaletteEntry", "alpha", DATATYPE_INTEGER, false, "255"); + + addElement("BackgroundIndex", "Chroma", CHILD_POLICY_EMPTY); + addAttribute("BackgroundIndex", "value", DATATYPE_INTEGER, true, null); + + addElement("BackgroundColor", "Chroma", CHILD_POLICY_EMPTY); + addAttribute("BackgroundColor", "red", DATATYPE_INTEGER, true, null); + addAttribute("BackgroundColor", "green", DATATYPE_INTEGER, true, null); + addAttribute("BackgroundColor", "blue", DATATYPE_INTEGER, true, null); + + // COMPRESSION + addElement("Compression", standardMetadataFormatName, CHILD_POLICY_SOME); + + addElement("CompressionTypeName", "Compression", CHILD_POLICY_EMPTY); + addAttribute("CompressionTypeName", "value", DATATYPE_STRING, true, null); + + addElement("Lossless", "Compression", CHILD_POLICY_EMPTY); + addBooleanAttribute("Lossless", "value", true, true); + + addElement("NumProgressiveScans", "Compression", CHILD_POLICY_EMPTY); + addAttribute("NumProgressiveScans", "value", DATATYPE_INTEGER, true, null); + + addElement("BitRate", "Compression", CHILD_POLICY_EMPTY); + addAttribute("BitRate", "value", DATATYPE_FLOAT, true, null); + + // DATA + addElement("Data", standardMetadataFormatName, CHILD_POLICY_SOME); + + addElement("PlanarConfiguration", "Data", CHILD_POLICY_EMPTY); + values = new ArrayList(4); + values.add("PixelInterleaved"); + values.add("PlaneInterleaved"); + values.add("LineInterleaved"); + values.add("TileInterleaved"); + addAttribute("PlanarConfiguration", "value", DATATYPE_STRING, true, null, values); + + addElement("SampleFormat", "Data", CHILD_POLICY_EMPTY); + values = new ArrayList(4); + values.add("SignedIntegral"); + values.add("UnsignedIntegral"); + values.add("Real"); + values.add("Index"); + addAttribute("SampleFormat", "value", DATATYPE_STRING, true, null, values); + + addElement("BitsPerSample", "Data", CHILD_POLICY_EMPTY); + addAttribute("BitsPerSample", "value", DATATYPE_INTEGER, true, 1, Integer.MAX_VALUE); // list + + addElement("SignificantBitsPerSample", "Data", CHILD_POLICY_EMPTY); + addAttribute("SignificantBitsPerSample", "value", DATATYPE_INTEGER, true, 1, + Integer.MAX_VALUE); // list + + addElement("SampleMSB", "Data", CHILD_POLICY_EMPTY); + addAttribute("SampleMSB", "value", DATATYPE_INTEGER, true, 1, Integer.MAX_VALUE); // list + + // DIMENSION + addElement("Dimension", standardMetadataFormatName, CHILD_POLICY_SOME); + + addElement("PixelAspectRatio", "Dimension", CHILD_POLICY_EMPTY); + addAttribute("PixelAspectRatio", "value", DATATYPE_FLOAT, true, null); + + addElement("ImageOrientation", "Dimension", CHILD_POLICY_EMPTY); + values = new ArrayList(8); + values.add("Normal"); + values.add("Rotate90"); + values.add("Rotate180"); + values.add("Rotate270"); + values.add("FlipH"); + values.add("FlipV"); + values.add("FlipHRotate90"); + values.add("FlipVRotate90"); + addAttribute("ImageOrientation", "value", DATATYPE_STRING, true, null, values); + + addElement("HorizontalPixelSize", "Dimension", CHILD_POLICY_EMPTY); + addAttribute("HorizontalPixelSize", "value", DATATYPE_FLOAT, true, null); + + addElement("VerticalPixelSize", "Dimension", CHILD_POLICY_EMPTY); + addAttribute("VerticalPixelSize", "value", DATATYPE_FLOAT, true, null); + + addElement("HorizontalPhysicalPixelSpacing", "Dimension", CHILD_POLICY_EMPTY); + addAttribute("HorizontalPhysicalPixelSpacing", "value", DATATYPE_FLOAT, true, null); + + addElement("VerticalPhysicalPixelSpacing", "Dimension", CHILD_POLICY_EMPTY); + addAttribute("VerticalPhysicalPixelSpacing", "value", DATATYPE_FLOAT, true, null); + + addElement("HorizontalPosition", "Dimension", CHILD_POLICY_EMPTY); + addAttribute("HorizontalPosition", "value", DATATYPE_FLOAT, true, null); + + addElement("VerticalPosition", "Dimension", CHILD_POLICY_EMPTY); + addAttribute("VerticalPosition", "value", DATATYPE_FLOAT, true, null); + + addElement("HorizontalPixelOffset", "Dimension", CHILD_POLICY_EMPTY); + addAttribute("HorizontalPixelOffset", "value", DATATYPE_INTEGER, true, null); + + addElement("VerticalPixelOffset", "Dimension", CHILD_POLICY_EMPTY); + addAttribute("VerticalPixelOffset", "value", DATATYPE_INTEGER, true, null); + + addElement("HorizontalScreenSize", "Dimension", CHILD_POLICY_EMPTY); + addAttribute("HorizontalScreenSize", "value", DATATYPE_INTEGER, true, null); + + addElement("VerticalScreenSize", "Dimension", CHILD_POLICY_EMPTY); + addAttribute("VerticalScreenSize", "value", DATATYPE_INTEGER, true, null); + + // DOCUMENT + addElement("Document", standardMetadataFormatName, CHILD_POLICY_SOME); + + addElement("FormatVersion", "Document", CHILD_POLICY_EMPTY); + addAttribute("FormatVersion", "value", DATATYPE_STRING, true, null); + + addElement("SubimageInterpretation", "Document", CHILD_POLICY_EMPTY); + values = new ArrayList(14); + values.add("Standalone"); + values.add("SinglePage"); + values.add("FullResolution"); + values.add("ReducedResolution"); + values.add("PyramidLayer"); + values.add("Preview"); + values.add("VolumeSlice"); + values.add("ObjectView"); + values.add("Panorama"); + values.add("AnimationFrame"); + values.add("TransparencyMask"); + values.add("CompositingLayer"); + values.add("SpectralSlice"); + values.add("Unknown"); + addAttribute("SubimageInterpretation", "value", DATATYPE_STRING, true, null, values); + + addElement("ImageCreationTime", "Document", CHILD_POLICY_EMPTY); + addAttribute("ImageCreationTime", "year", DATATYPE_INTEGER, true, null); + addAttribute("ImageCreationTime", "month", DATATYPE_INTEGER, true, null, "1", "12", true, + true); + addAttribute("ImageCreationTime", "day", DATATYPE_INTEGER, true, null, "1", "31", true, + true); + addAttribute("ImageCreationTime", "hour", DATATYPE_INTEGER, false, "0", "0", "23", true, + true); + addAttribute("ImageCreationTime", "minute", DATATYPE_INTEGER, false, "0", "0", "59", true, + true); + addAttribute("ImageCreationTime", "second", DATATYPE_INTEGER, false, "0", "0", "60", true, + true); + + addElement("ImageModificationTime", "Document", CHILD_POLICY_EMPTY); + addAttribute("ImageModificationTime", "year", DATATYPE_INTEGER, true, null); + addAttribute("ImageModificationTime", "month", DATATYPE_INTEGER, true, null, "1", "12", + true, true); + addAttribute("ImageModificationTime", "day", DATATYPE_INTEGER, true, null, "1", "31", true, + true); + addAttribute("ImageModificationTime", "hour", DATATYPE_INTEGER, false, "0", "0", "23", + true, true); + addAttribute("ImageModificationTime", "minute", DATATYPE_INTEGER, false, "0", "0", "59", + true, true); + addAttribute("ImageModificationTime", "second", DATATYPE_INTEGER, false, "0", "0", "60", + true, true); + + // TEXT + addElement("Text", standardMetadataFormatName, 0, Integer.MAX_VALUE); // CHILD_POLICY_REPEAT + + addElement("TextEntry", "Text", CHILD_POLICY_EMPTY); + addAttribute("TextEntry", "keyword", DATATYPE_STRING, false, null); + addAttribute("TextEntry", "value", DATATYPE_STRING, true, null); + addAttribute("TextEntry", "language", DATATYPE_STRING, false, null); + addAttribute("TextEntry", "encoding", DATATYPE_STRING, false, null); + values = new ArrayList(5); + values.add("none"); + values.add("lzw"); + values.add("zip"); + values.add("bzip"); + values.add("other"); + addAttribute("TextEntry", "compression", DATATYPE_STRING, false, "none", values); + + // TRANSPARENCY + addElement("Transparency", standardMetadataFormatName, CHILD_POLICY_SOME); + + addElement("Alpha", "Transparency", CHILD_POLICY_EMPTY); + values = new ArrayList(3); + values.add("none"); + values.add("premultiplied"); + values.add("nonpremultiplied"); + addAttribute("Alpha", "value", DATATYPE_STRING, false, "none", values); + + addElement("TransparentIndex", "Transparency", CHILD_POLICY_EMPTY); + addAttribute("TransparentIndex", "value", DATATYPE_INTEGER, true, null); + + addElement("TransparentColor", "Transparency", CHILD_POLICY_EMPTY); + addAttribute("TransparentColor", "value", DATATYPE_INTEGER, true, 0, Integer.MAX_VALUE); + + addElement("TileTransparencies", "Transparency", 0, Integer.MAX_VALUE); // CHILD_POLICY_REPEAT + + addElement("TransparentTile", "TileTransparencies", CHILD_POLICY_EMPTY); + addAttribute("TransparentTile", "x", DATATYPE_INTEGER, true, null); + addAttribute("TransparentTile", "y", DATATYPE_INTEGER, true, null); + + addElement("TileOpacities", "Transparency", 0, Integer.MAX_VALUE); // CHILD_POLICY_REPEAT + + addElement("OpaqueTile", "TileOpacities", CHILD_POLICY_EMPTY); + addAttribute("OpaqueTile", "x", DATATYPE_INTEGER, true, null); + addAttribute("OpaqueTile", "y", DATATYPE_INTEGER, true, null); + } +} diff --git a/app/src/main/java/javax/imageio/metadata/IIOStandardMetadataFormatResources.properties b/app/src/main/java/javax/imageio/metadata/IIOStandardMetadataFormatResources.properties new file mode 100644 index 000000000..d18580898 --- /dev/null +++ b/app/src/main/java/javax/imageio/metadata/IIOStandardMetadataFormatResources.properties @@ -0,0 +1,133 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Descriptions of elements and attributes of the plugin neutral metadata format +# (see IIOStandardMetadataFormat) + +# Messages for EN locale +Chroma=Chroma (color) information +ColorSpaceType=The raw color space of the image +ColorSpaceType/name=The raw color space of the image +NumChannels=The number of channels in the raw image, including alpha +NumChannels/value=The number of channels in the raw image, including alpha +Gamma=The image gamma +Gamma/value=The image gamma +BlackIsZero=True if smaller values represent darker shades +BlackIsZero/value=True if smaller values represent darker shades +Palette=Palette-color information +PaletteEntry=A palette entry +PaletteEntry/index=The index of the palette entry +PaletteEntry/red=The red value for the palette entry +PaletteEntry/green=The green value for the palette entry +PaletteEntry/blue=The blue value for the palette entry +PaletteEntry/alpha=The alpha value for the palette entry +BackgroundIndex=A palette index to be used as a background +BackgroundIndex/value=A palette index to be used as a background +BackgroundColor=An RGB triple to be used as a background +BackgroundColor/red=The red background value +BackgroundColor/green=The green background value +BackgroundColor/blue=The blue background value + +Compression=Compression information +CompressionTypeName=The name of the compression scheme in use +CompressionTypeName/value=The name of the compression scheme in use +Lossless=True if the compression scheme is lossless +Lossless/value=True if the compression scheme is lossless +NumProgressiveScans=The number of progressive scans used in the image encoding +NumProgressiveScans/value=The number of progressive scans used in the image encoding +BitRate=The estimated bit rate of the compression scheme +BitRate/value=The estimated bit rate of the compression scheme + +Data=Information on the image layout +PlanarConfiguration=The organization of image samples in the stream +PlanarConfiguration/value=The organization of image samples in the stream +SampleFormat=The numeric format of image samples +SampleFormat/value=The numeric format of image samples +BitsPerSample=The number of bits per sample +BitsPerSample/value=A list of integers, one per channel +SignificantBitsPerSample=The number of significant bits per sample +SignificantBitsPerSample/value=A list of integers, one per channel +SampleMSB=The position of the most significant bit of each sample +SampleMSB/value=A list of integers, one per channel + +Dimension=Dimension information +PixelAspectRatio=The width of a pixel divided by its height +PixelAspectRatio/value=The width of a pixel divided by its height +ImageOrientation=The desired orientation of the image in terms of flips and counter-clockwise rotations +ImageOrientation/value=The desired orientation of the image in terms of flips and counter-clockwise rotations +HorizontalPixelSize=The width of a pixel, in millimeters, as it should be rendered on media +HorizontalPixelSize/value=The width of a pixel, in millimeters, as it should be rendered on media +VerticalPixelSize=The height of a pixel, in millimeters, as it should be rendered on media +VerticalPixelSize/value=The height of a pixel, in millimeters, as it should be rendered on media +HorizontalPhysicalPixelSpacing=The horizontal distance in the subject of the image, in millimeters, represented by one pixel at the center of the image +HorizontalPhysicalPixelSpacing/value=The horizontal distance in the subject of the image, in millimeters, represented by one pixel at the center of the image +VerticalPhysicalPixelSpacing=The vertical distance in the subject of the image, in millimeters, represented by one pixel at the center of the image +VerticalPhysicalPixelSpacing/value=The vertical distance in the subject of the image, in millimeters, represented by one pixel at the center of the image +HorizontalPosition=The horizontal position, in millimeters, where the image should be rendered on media +HorizontalPosition/value=The horizontal position, in millimeters, where the image should be rendered on media +VerticalPosition=The vertical position, in millimeters, where the image should be rendered on media +VerticalPosition/value=The vertical position, in millimeters, where the image should be rendered on media +HorizontalPixelOffset=The horizonal position, in pixels, where the image should be rendered onto a raster display +HorizontalPixelOffset/value=The horizonal position, in pixels, where the image should be rendered onto a raster display +VerticalPixelOffset=The vertical position, in pixels, where the image should be rendered onto a raster display +VerticalPixelOffset/value=The vertical position, in pixels, where the image should be rendered onto a raster display +HorizontalScreenSize=The width, in pixels, of the raster display into which the image should be rendered +HorizontalScreenSize/value=The width, in pixels, of the raster display into which the image should be rendered +VerticalScreenSize=The height, in pixels, of the raster display into which the image should be rendered +VerticalScreenSize/value=The height, in pixels, of the raster display into which the image should be rendered + +Document=Document information +FormatVersion=The version of the format used by the stream +FormatVersion/value=The version of the format used by the stream +SubimageInterpretation=The interpretation of this image in relation to the other images stored in the same stream +SubimageInterpretation/value=The interpretation of this image in relation to the other images stored in the same stream +ImageCreationTime=The time of image creation +ImageCreationTime/year=The full year (e.g., 1967, not 67) +ImageCreationTime/month=The month, with January = 1 +ImageCreationTime/day=The day of the month +ImageCreationTime/hour=The hour from 0 to 23 +ImageCreationTime/minute=The minute from 0 to 59 +ImageCreationTime/second=The second from 0 to 60 (60 = leap second) +ImageModificationTime=The time of the last image modification +ImageModificationTime/year=The full year (e.g., 1967, not 67) +ImageModificationTime/month=The month, with January = 1 +ImageModificationTime/day=The day of the month +ImageModificationTime/hour=The hour from 0 to 23 +ImageModificationTime/minute=The minute from 0 to 59 +ImageModificationTime/second=The second from 0 to 60 (60 = leap second) + +Text=Text information +TextEntry=A text entry +TextEntry/keyword=A keyword associated with the text entry +TextEntry/value=the text entry +TextEntry/language=The language of the text +TextEntry/encoding=The encoding of the text +TextEntry/compression=The method used to compress the text + +Transparency=Transparency information +Alpha=The type of alpha information contained in the image +Alpha/value=The type of alpha information contained in the image +TransparentIndex=A palette index to be treated as transparent +TransparentIndex/value=A palette index to be treated as transparent +TransparentColor=An RGB color to be treated as transparent +TransparentColor/value=An RGB color to be treated as transparent +TileTransparencies=A list of completely transparent tiles +TransparentTile=The index of a completely transparent tile +TransparentTile/x=The tile's X index +TransparentTile/y=The tile's Y index +TileOpacities=A list of completely opaque tiles +OpaqueTile=The index of a completely opaque tile +OpaqueTile/x=The tile's X index +OpaqueTile/y=The tile's Y index diff --git a/app/src/main/java/javax/imageio/metadata/package.html b/app/src/main/java/javax/imageio/metadata/package.html new file mode 100644 index 000000000..29bd51b2c --- /dev/null +++ b/app/src/main/java/javax/imageio/metadata/package.html @@ -0,0 +1,8 @@ + + +

    + This package contains classes which allows to read and write describing metadata of image files. +

    + @since Android 1.0 + + diff --git a/app/src/main/java/javax/imageio/package.html b/app/src/main/java/javax/imageio/package.html new file mode 100644 index 000000000..2fd614874 --- /dev/null +++ b/app/src/main/java/javax/imageio/package.html @@ -0,0 +1,8 @@ + + +

    + This package contains classes and interfaces which provides an Image I/O API. The contained classes and interfaces allow reading and writing image files of different formats. +

    + @since Android 1.0 + + diff --git a/app/src/main/java/javax/imageio/plugins/bmp/BMPImageWriteParam.java b/app/src/main/java/javax/imageio/plugins/bmp/BMPImageWriteParam.java new file mode 100644 index 000000000..ecfb20ad3 --- /dev/null +++ b/app/src/main/java/javax/imageio/plugins/bmp/BMPImageWriteParam.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.imageio.plugins.bmp; + +import javax.imageio.ImageWriteParam; +import java.util.Locale; + +/** + * The BMPImageWriteParam class allows encoding an image in BMP format. + * + * @since Android 1.0 + */ +public class BMPImageWriteParam extends ImageWriteParam { + + /** + * The top down. + */ + private boolean topDown; // Default is bottom-up + + /** + * Instantiates a new BMPImageWriteParam with default values of all + * parameters. + */ + public BMPImageWriteParam() { + this(null); + } + + /** + * Instantiates a new BMPImageWriteParam with the specified Locale. + * + * @param locale + * the specified Locale. + */ + public BMPImageWriteParam(Locale locale) { + super(locale); + + // Set the compression + canWriteCompressed = true; + compressionTypes = new String[] { + "BI_RGB", "BI_RLE8", "BI_RLE4", "BI_BITFIELDS" + }; + compressionType = compressionTypes[0]; + } + + /** + * Sets true if the data will be written in a top-down order, false + * otherwise. + * + * @param topDown + * the new top-down value. + */ + public void setTopDown(boolean topDown) { + this.topDown = topDown; + } + + /** + * Returns true if the data is written in top-down order, false otherwise. + * + * @return true if the data is written in top-down order, false otherwise. + */ + public boolean isTopDown() { + return topDown; + } +} diff --git a/app/src/main/java/javax/imageio/plugins/bmp/package.html b/app/src/main/java/javax/imageio/plugins/bmp/package.html new file mode 100644 index 000000000..9494a102d --- /dev/null +++ b/app/src/main/java/javax/imageio/plugins/bmp/package.html @@ -0,0 +1,8 @@ + + +

    + This package contains auxiliary classes for the built-in BMP image plug-in. +

    + @since Android 1.0 + + diff --git a/app/src/main/java/javax/imageio/plugins/jpeg/JPEGHuffmanTable.java b/app/src/main/java/javax/imageio/plugins/jpeg/JPEGHuffmanTable.java new file mode 100644 index 000000000..4335228d9 --- /dev/null +++ b/app/src/main/java/javax/imageio/plugins/jpeg/JPEGHuffmanTable.java @@ -0,0 +1,226 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.imageio.plugins.jpeg; + +/** + * The JPEGHuffmanTable class represents a single JPEG Huffman table. It + * contains the standard tables from the JPEG specification. + * + * @since Android 1.0 + */ +public class JPEGHuffmanTable { + + /** + * The standard DC luminance Huffman table . + */ + public static final JPEGHuffmanTable StdDCLuminance = new JPEGHuffmanTable(new short[] { + 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 + }, new short[] { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0x0A, 0x0B + }, false); + + /** + * The standard DC chrominance Huffman table. + */ + public static final JPEGHuffmanTable StdDCChrominance = new JPEGHuffmanTable(new short[] { + 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 + }, new short[] { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0x0A, 0x0B + }, false); + + /** + * The standard AC luminance Huffman table. + */ + public static final JPEGHuffmanTable StdACLuminance = new JPEGHuffmanTable(new short[] { + 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7D + }, new short[] { + 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 + }, false); + + /** + * The standard AC chrominance Huffman table. + */ + public static final JPEGHuffmanTable StdACChrominance = new JPEGHuffmanTable(new short[] { + 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 + }, new short[] { + 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 + }, false); + + /** + * The lengths. + */ + private short lengths[]; + + /** + * The values. + */ + private short values[]; + + /** + * Instantiates a new jPEG huffman table. + * + * @param lengths + * the lengths + * @param values + * the values + * @param copy + * the copy + */ + JPEGHuffmanTable(short[] lengths, short[] values, boolean copy) { + // Construction of standard tables without checks + // The third param is dummy + // Could be also used for copying of the existing tables + this.lengths = lengths; + this.values = values; + } + + /** + * Instantiates a new JPEGHuffmanTable. + * + * @param lengths + * the array of shorts lengths. + * @param values + * the array of shorts containing the values in order of + * increasing code length. + */ + public JPEGHuffmanTable(short[] lengths, short[] values) { + if (lengths == null) { + throw new IllegalArgumentException("lengths array is null!"); + } + if (values == null) { + throw new IllegalArgumentException("values array is null!"); + } + if (lengths.length > 16) { // According to the spec + throw new IllegalArgumentException("lengths array is too long!"); + } + if (values.length > 256) { // According to the spec + throw new IllegalArgumentException("values array is too long"); + } + for (short length : lengths) { + if (length < 0) { + throw new IllegalArgumentException("Values in lengths array must be non-negative."); + } + } + for (short value : values) { + if (value < 0) { + throw new IllegalArgumentException("Values in values array must be non-negative."); + } + } + + checkHuffmanTable(lengths, values); + + this.lengths = new short[lengths.length]; + this.values = new short[values.length]; + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(lengths, 0, this.lengths, 0, lengths.length); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(values, 0, this.values, 0, values.length); + } + + /** + * Gets an array of lengths in the Huffman table. + * + * @return the array of short values representing the length values in the + * Huffman table. + */ + public short[] getLengths() { + short newLengths[] = new short[lengths.length]; + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(lengths, 0, newLengths, 0, lengths.length); + return newLengths; + } + + /** + * Gets an array of values represented by increasing length of their codes. + * + * @return the array of values. + */ + public short[] getValues() { + short newValues[] = new short[values.length]; + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(values, 0, newValues, 0, values.length); + return newValues; + } + + /** + * Check huffman table. + * + * @param lengths + * the lengths. + * @param values + * the values. + */ + private static void checkHuffmanTable(short[] lengths, short[] values) { + int numLeaves = 0; + int possibleLeaves = 2; + for (short length : lengths) { + numLeaves += length; + possibleLeaves -= length; + if (possibleLeaves < 0) { + throw new IllegalArgumentException( + "Invalid Huffman table provided, lengths are incorrect."); + } + possibleLeaves <<= 1; + } + + if (values.length != numLeaves) { + throw new IllegalArgumentException( + "Invalid Huffman table provided, sum of lengths != values."); + } + } + + /** + * Returns the string representation of this JPEGHuffmanTable object. + * + * @return the string representation of this JPEGHuffmanTable object. + */ + @Override + public String toString() { + StringBuffer sb = new StringBuffer(); + + sb.append("JPEGHuffmanTable:\nlengths:"); + for (short length : lengths) { + sb.append(' ').append(length); + } + + sb.append("\nvalues:"); + for (short value : values) { + sb.append(' ').append(value); + } + + return sb.toString(); + } +} diff --git a/app/src/main/java/javax/imageio/plugins/jpeg/JPEGImageReadParam.java b/app/src/main/java/javax/imageio/plugins/jpeg/JPEGImageReadParam.java new file mode 100644 index 000000000..2f3a9a8fb --- /dev/null +++ b/app/src/main/java/javax/imageio/plugins/jpeg/JPEGImageReadParam.java @@ -0,0 +1,123 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.imageio.plugins.jpeg; + +import javax.imageio.ImageReadParam; + +/** + * The JPEGImageReadParam class provides functionality to set Huffman tables and + * quantization tables when using the JPEG reader plug-in. + * + * @since Android 1.0 + */ +public class JPEGImageReadParam extends ImageReadParam { + + /** + * The q tables. + */ + private JPEGQTable qTables[]; + + /** + * The dc huffman tables. + */ + private JPEGHuffmanTable dcHuffmanTables[]; + + /** + * The ac huffman tables. + */ + private JPEGHuffmanTable acHuffmanTables[]; + + /** + * Instantiates a new JPEGImageReadParam. + */ + public JPEGImageReadParam() { + } + + /** + * Returns true if tables are set, false otherwise. + * + * @return true, if tables are set, false otherwise. + */ + public boolean areTablesSet() { + return qTables != null; + } + + /** + * Sets the quantization and Huffman tables for using in decoding streams. + * + * @param qTables + * the quantization tables. + * @param DCHuffmanTables + * the standart DC Huffman tables. + * @param ACHuffmanTables + * the standart AC huffman tables. + */ + public void setDecodeTables(JPEGQTable[] qTables, JPEGHuffmanTable[] DCHuffmanTables, + JPEGHuffmanTable[] ACHuffmanTables) { + if (qTables == null || DCHuffmanTables == null || ACHuffmanTables == null) { + throw new IllegalArgumentException("Invalid JPEG table arrays"); + } + if (DCHuffmanTables.length != ACHuffmanTables.length) { + throw new IllegalArgumentException("Invalid JPEG table arrays"); + } + if (qTables.length > 4 || DCHuffmanTables.length > 4) { + throw new IllegalArgumentException("Invalid JPEG table arrays"); + } + + // Do the shallow copy, it should be enough + this.qTables = qTables.clone(); + dcHuffmanTables = DCHuffmanTables.clone(); + acHuffmanTables = ACHuffmanTables.clone(); + } + + /** + * Unset all decoded tables. + */ + public void unsetDecodeTables() { + qTables = null; + dcHuffmanTables = null; + acHuffmanTables = null; + } + + /** + * Gets the quantization tables. + * + * @return the quantization tables, or null. + */ + public JPEGQTable[] getQTables() { + return qTables == null ? null : qTables.clone(); + } + + /** + * Gets the DC Huffman tables. + * + * @return the DC Huffman tables which are set, or null. + */ + public JPEGHuffmanTable[] getDCHuffmanTables() { + return dcHuffmanTables == null ? null : dcHuffmanTables.clone(); + } + + /** + * Gets the AC Huffman tables. + * + * @return the AC Huffman tables which are set, or null. + */ + public JPEGHuffmanTable[] getACHuffmanTables() { + return acHuffmanTables == null ? null : acHuffmanTables.clone(); + } +} diff --git a/app/src/main/java/javax/imageio/plugins/jpeg/JPEGImageWriteParam.java b/app/src/main/java/javax/imageio/plugins/jpeg/JPEGImageWriteParam.java new file mode 100644 index 000000000..b9799112e --- /dev/null +++ b/app/src/main/java/javax/imageio/plugins/jpeg/JPEGImageWriteParam.java @@ -0,0 +1,209 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.imageio.plugins.jpeg; + +import org.apache.harmony.x.imageio.plugins.jpeg.JPEGConsts; + +import javax.imageio.ImageWriteParam; +import java.util.Locale; + +/** + * The JPEGImageWriteParam class allows to set JPEG Huffman tables and + * quantization when using the JPEG writer plug-in. + * + * @since Android 1.0 + */ +public class JPEGImageWriteParam extends ImageWriteParam { + + /** + * The Constant COMP_QUALITY_VALUES. + */ + private static final float[] COMP_QUALITY_VALUES = { + 0.05f, 0.75f, 0.95f + }; + + /** + * The Constant COMP_QUALITY_DESCRIPTIONS. + */ + private static final String[] COMP_QUALITY_DESCRIPTIONS = { + "Minimum useful", "Visually lossless", "Maximum useful" + }; + + /** + * The q tables. + */ + private JPEGQTable[] qTables; + + /** + * The dc huffman tables. + */ + private JPEGHuffmanTable[] dcHuffmanTables; + + /** + * The ac huffman tables. + */ + private JPEGHuffmanTable[] acHuffmanTables; + + /** + * The optimize huffman tables. + */ + private boolean optimizeHuffmanTables; + + /** + * Instantiates a new JPEGImageWriteParam object with the specified Locale. + * + * @param locale + * the Locale. + */ + public JPEGImageWriteParam(Locale locale) { + super(locale); + + canWriteProgressive = true; + progressiveMode = ImageWriteParam.MODE_DISABLED; + + canWriteCompressed = true; + compressionTypes = new String[] { + "JPEG" + }; + compressionType = compressionTypes[0]; + compressionQuality = JPEGConsts.DEFAULT_JPEG_COMPRESSION_QUALITY; + } + + /** + * Returns true if tables are set, false otherwise. + * + * @return true, if tables are set, false otherwise. + */ + public boolean areTablesSet() { + return qTables != null; + } + + /** + * Sets the quantization and Huffman tables for using in encoding streams. + * + * @param qTables + * the quantization tables. + * @param DCHuffmanTables + * the standart DC Huffman tables. + * @param ACHuffmanTables + * the standart AC huffman tables. + */ + public void setEncodeTables(JPEGQTable[] qTables, JPEGHuffmanTable[] DCHuffmanTables, + JPEGHuffmanTable[] ACHuffmanTables) { + if (qTables == null || DCHuffmanTables == null || ACHuffmanTables == null) { + throw new IllegalArgumentException("Invalid JPEG table arrays"); + } + if (DCHuffmanTables.length != ACHuffmanTables.length) { + throw new IllegalArgumentException("Invalid JPEG table arrays"); + } + if (qTables.length > 4 || DCHuffmanTables.length > 4) { + throw new IllegalArgumentException("Invalid JPEG table arrays"); + } + + // Do the shallow copy, it should be enough + this.qTables = qTables.clone(); + dcHuffmanTables = DCHuffmanTables.clone(); + acHuffmanTables = ACHuffmanTables.clone(); + } + + /** + * Unset all encoded tables. + */ + public void unsetEncodeTables() { + qTables = null; + dcHuffmanTables = null; + acHuffmanTables = null; + } + + /** + * Gets the DC Huffman tables. + * + * @return the DC Huffman tables which are set, or null. + */ + public JPEGHuffmanTable[] getDCHuffmanTables() { + return dcHuffmanTables == null ? null : dcHuffmanTables.clone(); + } + + /** + * Gets the AC Huffman tables. + * + * @return the AC Huffman tables which are set, or null. + */ + public JPEGHuffmanTable[] getACHuffmanTables() { + return acHuffmanTables == null ? null : acHuffmanTables.clone(); + } + + /** + * Gets the quantization tables. + * + * @return the quantization tables, or null. + */ + public JPEGQTable[] getQTables() { + return qTables == null ? null : qTables.clone(); + } + + @Override + public String[] getCompressionQualityDescriptions() { + super.getCompressionQualityDescriptions(); + return COMP_QUALITY_DESCRIPTIONS.clone(); + } + + @Override + public float[] getCompressionQualityValues() { + super.getCompressionQualityValues(); + return COMP_QUALITY_VALUES.clone(); + } + + /** + * Sets the flag indicated that the writer will generate optimized Huffman + * tables for the image as part of the writing process. + * + * @param optimize + * the flag of optimizing huffman tables. + */ + public void setOptimizeHuffmanTables(boolean optimize) { + optimizeHuffmanTables = optimize; + } + + /** + * Returns true if the writer generates optimized Huffman tables, false + * otherwise. + * + * @return true, if the writer generates optimized Huffman tables, false + * otherwise. + */ + public boolean getOptimizeHuffmanTables() { + return optimizeHuffmanTables; + } + + @Override + public boolean isCompressionLossless() { + if (getCompressionMode() != MODE_EXPLICIT) { + throw new IllegalStateException("Compression mode not MODE_EXPLICIT!"); + } + return false; + } + + @Override + public void unsetCompression() { + if (getCompressionMode() != MODE_EXPLICIT) { + throw new IllegalStateException("Compression mode not MODE_EXPLICIT!"); + } + compressionQuality = JPEGConsts.DEFAULT_JPEG_COMPRESSION_QUALITY; + } +} diff --git a/app/src/main/java/javax/imageio/plugins/jpeg/JPEGQTable.java b/app/src/main/java/javax/imageio/plugins/jpeg/JPEGQTable.java new file mode 100644 index 000000000..3461d4669 --- /dev/null +++ b/app/src/main/java/javax/imageio/plugins/jpeg/JPEGQTable.java @@ -0,0 +1,165 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.3 $ + */ + +package javax.imageio.plugins.jpeg; + +/** + * The JPEGQTable class represents a single JPEG quantization table and provides + * for the standard tables taken from the JPEG specification. + * + * @since Android 1.0 + */ +public class JPEGQTable { + + /** + * The Constant SIZE. + */ + private final static int SIZE = 64; + + /** + * The Constant BASELINE_MAX. + */ + private final static int BASELINE_MAX = 255; + + /** + * The Constant MAX. + */ + private final static int MAX = 32767; + + /** + * The table. + */ + private int[] theTable; + + /* + * K1 & K2 tables can be found in the JPEG format specification at + * http://www.w3.org/Graphics/JPEG/itu-t81.pdf + */ + + /** + * The Constant K1LumTable. + */ + private static final int[] K1LumTable = new int[] { + 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 + }; + + /** + * The Constant K2ChrTable. + */ + private static final int[] K2ChrTable = new int[] { + 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 + }; + + /** + * The K1Luminance indicates standard table K.1 from JPEG specification and + * produces "good" quality output. + */ + public static final JPEGQTable K1Luminance = new JPEGQTable(K1LumTable); + + /** + * The K1Div2Luminance indicates K.1 table from JPEG specification with all + * elements divided by 2 and produces "very good" quality output. + */ + public static final JPEGQTable K1Div2Luminance = K1Luminance.getScaledInstance(0.5f, true); + + /** + * The K2Chrominance indicates K.2 table from JPEG specification and + * produces "good" quality output. + */ + public static final JPEGQTable K2Chrominance = new JPEGQTable(K2ChrTable); + + /** + * The Constant K2Div2Chrominance indicates K.2 table from JPEG + * specification with all elements divided by 2 and produces "very good" + * quality output. + */ + public static final JPEGQTable K2Div2Chrominance = K2Chrominance.getScaledInstance(0.5f, true);; + + /** + * Instantiates a new JPEGQTable from the array, which should contain 64 + * elements in natural order. + * + * @param table + * the quantization table. + */ + public JPEGQTable(int[] table) { + if (table == null) { + throw new IllegalArgumentException("table should not be NULL"); + } + if (table.length != SIZE) { + throw new IllegalArgumentException("illegal table size: " + table.length); + } + theTable = table.clone(); + } + + /** + * Gets the current quantization table as an array of integer values. + * + * @return the current quantization table as an array of integer values. + */ + public int[] getTable() { + return theTable.clone(); + } + + /** + * Gets the scaled instance as quantization table where the values are + * multiplied by the scaleFactor and then clamped if forceBaseline is true. + * + * @param scaleFactor + * the scale factor of table. + * @param forceBaseline + * the force baseline flag, the values should be clamped if true. + * @return the new quantization table. + */ + public JPEGQTable getScaledInstance(float scaleFactor, boolean forceBaseline) { + int table[] = new int[SIZE]; + + int maxValue = forceBaseline ? BASELINE_MAX : MAX; + + for (int i = 0; i < theTable.length; i++) { + int rounded = Math.round(theTable[i] * scaleFactor); + if (rounded < 1) { + rounded = 1; + } + if (rounded > maxValue) { + rounded = maxValue; + } + table[i] = rounded; + } + return new JPEGQTable(table); + } + + /** + * Returns the string representation of this JPEGQTable object. + * + * @return the string representation of this JPEGQTable object. + */ + @Override + public String toString() { + // -- TODO more informative info + return "JPEGQTable"; + } +} diff --git a/app/src/main/java/javax/imageio/plugins/jpeg/package.html b/app/src/main/java/javax/imageio/plugins/jpeg/package.html new file mode 100644 index 000000000..14575c417 --- /dev/null +++ b/app/src/main/java/javax/imageio/plugins/jpeg/package.html @@ -0,0 +1,8 @@ + + +

    + This package contains auxiliary classes for the built-in JPEG image plug-in. +

    + @since Android 1.0 + + diff --git a/app/src/main/java/javax/imageio/spi/IIORegistry.java b/app/src/main/java/javax/imageio/spi/IIORegistry.java new file mode 100644 index 000000000..01ddeaafe --- /dev/null +++ b/app/src/main/java/javax/imageio/spi/IIORegistry.java @@ -0,0 +1,115 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.3 $ + */ + +package javax.imageio.spi; + +import java.util.Arrays; + +import org.apache.harmony.x.imageio.plugins.jpeg.JPEGImageReaderSpi; +import org.apache.harmony.x.imageio.plugins.jpeg.JPEGImageWriterSpi; +import org.apache.harmony.x.imageio.plugins.png.PNGImageReaderSpi; +import org.apache.harmony.x.imageio.plugins.png.PNGImageWriterSpi; +import org.apache.harmony.x.imageio.spi.FileIISSpi; +import org.apache.harmony.x.imageio.spi.FileIOSSpi; +import org.apache.harmony.x.imageio.spi.InputStreamIISSpi; +import org.apache.harmony.x.imageio.spi.OutputStreamIOSSpi; +import org.apache.harmony.x.imageio.spi.RAFIISSpi; +import org.apache.harmony.x.imageio.spi.RAFIOSSpi; + +/* + * @author Rustem V. Rafikov, Viskov Nikolay + * @version $Revision: 1.3 $ + */ + +/** + * The IIORegistry class registers service provider instances (SPI). Service + * provider instances are recognized by specific meta-information in the JAR + * files containing them. The JAR files with SPI classes are loaded from the + * application class path. + * + * @since Android 1.0 + */ +public final class IIORegistry extends ServiceRegistry { + + /** + * The instance. + */ + private static IIORegistry instance; + + /** + * The Constant CATEGORIES. + */ + private static final Class[] CATEGORIES = new Class[] { + javax.imageio.spi.ImageWriterSpi.class, javax.imageio.spi.ImageReaderSpi.class, + javax.imageio.spi.ImageInputStreamSpi.class, + // javax.imageio.spi.ImageTranscoderSpi.class, + javax.imageio.spi.ImageOutputStreamSpi.class + }; + + /** + * Instantiates a new IIO registry. + */ + private IIORegistry() { + super(Arrays.> asList(CATEGORIES).iterator()); + registerBuiltinSpis(); + registerApplicationClasspathSpis(); + } + + /** + * Register built-in SPIs. + */ + private void registerBuiltinSpis() { + registerServiceProvider(new JPEGImageWriterSpi()); + registerServiceProvider(new JPEGImageReaderSpi()); + registerServiceProvider(new PNGImageReaderSpi()); + registerServiceProvider(new PNGImageWriterSpi()); + registerServiceProvider(new FileIOSSpi()); + registerServiceProvider(new FileIISSpi()); + registerServiceProvider(new RAFIOSSpi()); + registerServiceProvider(new RAFIISSpi()); + registerServiceProvider(new OutputStreamIOSSpi()); + registerServiceProvider(new InputStreamIISSpi()); + // -- TODO implement + } + + /** + * Gets the default IIORegistry instance. + * + * @return the default IIORegistry instance. + */ + public static IIORegistry getDefaultInstance() { + // TODO implement own instance for each ThreadGroup (see also + // ThreadLocal) + synchronized (IIORegistry.class) { + if (instance == null) { + instance = new IIORegistry(); + } + return instance; + } + } + + /** + * Registers all service providers from the application class path. + */ + public void registerApplicationClasspathSpis() { + // -- TODO implement for non-builtin plugins + } +} diff --git a/app/src/main/java/javax/imageio/spi/IIOServiceProvider.java b/app/src/main/java/javax/imageio/spi/IIOServiceProvider.java new file mode 100644 index 000000000..e9476773a --- /dev/null +++ b/app/src/main/java/javax/imageio/spi/IIOServiceProvider.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.3 $ + */ + +package javax.imageio.spi; + +import java.util.Locale; + +/** + * The IIOServiceProvider abstract class provides base functionality for ImageIO + * service provider interfaces (SPIs). + * + * @since Android 1.0 + */ +public abstract class IIOServiceProvider implements RegisterableService { + + /** + * The vendor name of this service provider. + */ + protected String vendorName; + + /** + * The version of this service provider. + */ + protected String version; + + /** + * Instantiates a new IIOServiceProvider. + * + * @param vendorName + * the vendor name of service provider. + * @param version + * the version of service provider. + */ + public IIOServiceProvider(String vendorName, String version) { + if (vendorName == null) { + throw new NullPointerException("vendor name cannot be NULL"); + } + if (version == null) { + throw new NullPointerException("version name cannot be NULL"); + } + this.vendorName = vendorName; + this.version = version; + } + + /** + * Instantiates a new IIOServiceProvider. + */ + public IIOServiceProvider() { + throw new UnsupportedOperationException("Not supported yet"); + } + + public void onRegistration(ServiceRegistry registry, Class category) { + // the default impl. does nothing + } + + public void onDeregistration(ServiceRegistry registry, Class category) { + throw new UnsupportedOperationException("Not supported yet"); + } + + /** + * Gets the vendor name of this service provider. + * + * @return the vendor name of this service provider. + */ + public String getVendorName() { + return vendorName; + } + + /** + * Gets the version of this service provider. + * + * @return the version of this service provider. + */ + public String getVersion() { + return version; + } + + /** + * Gets a description of this service provider. The result string should be + * localized for the specified Locale. + * + * @param locale + * the specified Locale. + * @return the description of this service provider. + */ + public abstract String getDescription(Locale locale); +} diff --git a/app/src/main/java/javax/imageio/spi/ImageInputStreamSpi.java b/app/src/main/java/javax/imageio/spi/ImageInputStreamSpi.java new file mode 100644 index 000000000..fc859a871 --- /dev/null +++ b/app/src/main/java/javax/imageio/spi/ImageInputStreamSpi.java @@ -0,0 +1,131 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.3 $ + */ + +package javax.imageio.spi; + +import java.io.File; +import java.io.IOException; +import javax.imageio.stream.ImageInputStream; + +/** + * The ImageInputStreamSpi abstract class is a service provider interface (SPI) + * for ImageInputStreams. + * + * @since Android 1.0 + */ +public abstract class ImageInputStreamSpi extends IIOServiceProvider implements RegisterableService { + + /** + * The input class. + */ + protected Class inputClass; + + /** + * Instantiates a new ImageInputStreamSpi. + */ + protected ImageInputStreamSpi() { + throw new UnsupportedOperationException("Not supported yet"); + } + + /** + * Instantiates a new ImageInputStreamSpi. + * + * @param vendorName + * the vendor name. + * @param version + * the version. + * @param inputClass + * the input class. + */ + public ImageInputStreamSpi(String vendorName, String version, Class inputClass) { + super(vendorName, version); + this.inputClass = inputClass; + } + + /** + * Gets an input Class object that represents class or interface that must + * be implemented by an input source. + * + * @return the input class. + */ + public Class getInputClass() { + return inputClass; + } + + /** + * Returns true if the ImageInputStream can use a cache file. If this method + * returns false, the value of the useCache parameter of + * createInputStreamInstance will be ignored. The default implementation + * returns false. + * + * @return true, if the ImageInputStream can use a cache file, false + * otherwise. + */ + public boolean canUseCacheFile() { + return false; // -- def + } + + /** + * Returns true if the ImageInputStream implementation requires the use of a + * cache file. The default implementation returns false. + * + * @return true, if the ImageInputStream implementation requires the use of + * a cache file, false otherwise. + */ + public boolean needsCacheFile() { + return false; // def + } + + /** + * Creates the ImageInputStream associated with this service provider. The + * input object should be an instance of the class returned by the + * getInputClass method. This method uses the specified directory for the + * cache file if the useCache parameter is true. + * + * @param input + * the input Object. + * @param useCache + * the flag indicating if a cache file is needed or not. + * @param cacheDir + * the cache directory. + * @return the ImageInputStream. + * @throws IOException + * if an I/O exception has occurred. + */ + public abstract ImageInputStream createInputStreamInstance(Object input, boolean useCache, + File cacheDir) throws IOException; + + /** + * Creates the ImageInputStream associated with this service provider. The + * input object should be an instance of the class returned by getInputClass + * method. This method uses the default system directory for the cache file, + * if it is needed. + * + * @param input + * the input Object. + * @return the ImageInputStream. + * @throws IOException + * if an I/O exception has occurred. + */ + public ImageInputStream createInputStreamInstance(Object input) throws IOException { + return createInputStreamInstance(input, true, null); + } +} diff --git a/app/src/main/java/javax/imageio/spi/ImageOutputStreamSpi.java b/app/src/main/java/javax/imageio/spi/ImageOutputStreamSpi.java new file mode 100644 index 000000000..b7a9a5c33 --- /dev/null +++ b/app/src/main/java/javax/imageio/spi/ImageOutputStreamSpi.java @@ -0,0 +1,132 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.3 $ + */ + +package javax.imageio.spi; + +import javax.imageio.stream.ImageOutputStream; +import java.io.IOException; +import java.io.File; + +/** + * The ImageOutputStreamSpi abstract class is a service provider interface (SPI) + * for ImageOutputStreams. + * + * @since Android 1.0 + */ +public abstract class ImageOutputStreamSpi extends IIOServiceProvider implements + RegisterableService { + + /** + * The output class. + */ + protected Class outputClass; + + /** + * Instantiates a new ImageOutputStreamSpi. + */ + protected ImageOutputStreamSpi() { + throw new UnsupportedOperationException("Not supported yet"); + } + + /** + * Instantiates a new ImageOutputStreamSpi. + * + * @param vendorName + * the vendor name. + * @param version + * the version. + * @param outputClass + * the output class. + */ + public ImageOutputStreamSpi(String vendorName, String version, Class outputClass) { + super(vendorName, version); + this.outputClass = outputClass; + } + + /** + * Gets an output Class object that represents the class or interface that + * must be implemented by an output source. + * + * @return the output class. + */ + public Class getOutputClass() { + return outputClass; + } + + /** + * Returns true if the ImageOutputStream can use a cache file. If this + * method returns false, the value of the useCache parameter of + * createOutputStreamInstance will be ignored. The default implementation + * returns false. + * + * @return true, if the ImageOutputStream can use a cache file, false + * otherwise. + */ + public boolean canUseCacheFile() { + return false; // def + } + + /** + * Returns true if the ImageOutputStream implementation requires the use of + * a cache file. The default implementation returns false. + * + * @return true, if the ImageOutputStream implementation requires the use of + * a cache file, false otherwise. + */ + public boolean needsCacheFile() { + return false; // def + } + + /** + * Creates the ImageOutputStream associated with this service provider. The + * output object should be an instance of the class returned by + * getOutputClass method. This method uses the default system directory for + * the cache file, if it is needed. + * + * @param output + * the output Object. + * @return the ImageOutputStream. + * @throws IOException + * if an I/O exception has occurred. + */ + public ImageOutputStream createOutputStreamInstance(Object output) throws IOException { + return createOutputStreamInstance(output, true, null); + } + + /** + * Creates the ImageOutputStream associated with this service provider. The + * output object should be an instance of the class returned by + * getInputClass method. This method uses the specified directory for the + * cache file, if the useCache parameter is true. + * + * @param output + * the output Object. + * @param useCache + * the flag indicating if cache file is needed or not. + * @param cacheDir + * the cache directory. + * @return the ImageOutputStream. + * @throws IOException + * if an I/O exception has occurred. + */ + public abstract ImageOutputStream createOutputStreamInstance(Object output, boolean useCache, + File cacheDir) throws IOException; +} diff --git a/app/src/main/java/javax/imageio/spi/ImageReaderSpi.java b/app/src/main/java/javax/imageio/spi/ImageReaderSpi.java new file mode 100644 index 000000000..0528d250b --- /dev/null +++ b/app/src/main/java/javax/imageio/spi/ImageReaderSpi.java @@ -0,0 +1,204 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.3 $ + */ + +package javax.imageio.spi; + +import javax.imageio.stream.ImageInputStream; +import javax.imageio.ImageReader; +import java.io.IOException; + +/** + * The ImageReaderSpi abstract class is a service provider interface (SPI) for + * ImageReaders. + * + * @since Android 1.0 + */ +public abstract class ImageReaderSpi extends ImageReaderWriterSpi { + + /** + * The STANDARD_INPUT_TYPE contains ImageInputStream.class. + */ + public static final Class[] STANDARD_INPUT_TYPE = new Class[] { + ImageInputStream.class + }; + + /** + * The input types. + */ + protected Class[] inputTypes; + + /** + * The writer SPI names. + */ + protected String[] writerSpiNames; + + /** + * Instantiates a new ImageReaderSpi. + */ + protected ImageReaderSpi() { + throw new UnsupportedOperationException("Not supported yet"); + } + + /** + * Instantiates a new ImageReaderSpi. + * + * @param vendorName + * the vendor name. + * @param version + * the version. + * @param names + * the format names. + * @param suffixes + * the array of strings representing the file suffixes. + * @param MIMETypes + * the an array of strings representing MIME types. + * @param pluginClassName + * the plug-in class name. + * @param inputTypes + * the input types. + * @param writerSpiNames + * the array of strings with class names of all associated + * ImageWriters. + * @param supportsStandardStreamMetadataFormat + * the value indicating if stream metadata can be described by + * standard metadata format. + * @param nativeStreamMetadataFormatName + * the native stream metadata format name, returned by + * getNativeStreamMetadataFormatName. + * @param nativeStreamMetadataFormatClassName + * the native stream metadata format class name, returned by + * getNativeStreamMetadataFormat. + * @param extraStreamMetadataFormatNames + * the extra stream metadata format names, returned by + * getExtraStreamMetadataFormatNames. + * @param extraStreamMetadataFormatClassNames + * the extra stream metadata format class names, returned by + * getStreamMetadataFormat. + * @param supportsStandardImageMetadataFormat + * the value indicating if image metadata can be described by + * standard metadata format. + * @param nativeImageMetadataFormatName + * the native image metadata format name, returned by + * getNativeImageMetadataFormatName. + * @param nativeImageMetadataFormatClassName + * the native image metadata format class name, returned by + * getNativeImageMetadataFormat. + * @param extraImageMetadataFormatNames + * the extra image metadata format names, returned by + * getExtraImageMetadataFormatNames. + * @param extraImageMetadataFormatClassNames + * the extra image metadata format class names, returned by + * getImageMetadataFormat. + */ + public ImageReaderSpi(String vendorName, String version, String[] names, String[] suffixes, + String[] MIMETypes, String pluginClassName, Class[] inputTypes, + String[] writerSpiNames, boolean supportsStandardStreamMetadataFormat, + String nativeStreamMetadataFormatName, String nativeStreamMetadataFormatClassName, + String[] extraStreamMetadataFormatNames, String[] extraStreamMetadataFormatClassNames, + boolean supportsStandardImageMetadataFormat, String nativeImageMetadataFormatName, + String nativeImageMetadataFormatClassName, String[] extraImageMetadataFormatNames, + String[] extraImageMetadataFormatClassNames) { + super(vendorName, version, names, suffixes, MIMETypes, pluginClassName, + supportsStandardStreamMetadataFormat, nativeStreamMetadataFormatName, + nativeStreamMetadataFormatClassName, extraStreamMetadataFormatNames, + extraStreamMetadataFormatClassNames, supportsStandardImageMetadataFormat, + nativeImageMetadataFormatName, nativeImageMetadataFormatClassName, + extraImageMetadataFormatNames, extraImageMetadataFormatClassNames); + + if (inputTypes == null || inputTypes.length == 0) { + throw new NullPointerException("input types array cannot be NULL or empty"); + } + this.inputTypes = inputTypes; + this.writerSpiNames = writerSpiNames; + } + + /** + * Gets an array of Class objects whose types can be used as input for this + * reader. + * + * @return the input types. + */ + public Class[] getInputTypes() { + return inputTypes; + } + + /** + * Returns true if the format of source object is supported by this reader. + * + * @param source + * the source object to be decoded (for example an + * ImageInputStream). + * @return true, if the format of source object is supported by this reader, + * false otherwise. + * @throws IOException + * if an I/O exception has occurred. + */ + public abstract boolean canDecodeInput(Object source) throws IOException; + + /** + * Returns an instance of the ImageReader implementation for this service + * provider. + * + * @return the ImageReader. + * @throws IOException + * if an I/O exception has occurred. + */ + public ImageReader createReaderInstance() throws IOException { + return createReaderInstance(null); + } + + /** + * Returns an instance of the ImageReader implementation for this service + * provider. + * + * @param extension + * the a plug-in specific extension object, or null. + * @return the ImageReader. + * @throws IOException + * if an I/O exception has occurred. + */ + public abstract ImageReader createReaderInstance(Object extension) throws IOException; + + /** + * Checks whether or not the specified ImageReader object is an instance of + * the ImageReader associated with this service provider or not. + * + * @param reader + * the ImageReader. + * @return true, if the specified ImageReader object is an instance of the + * ImageReader associated with this service provider, false + * otherwise. + */ + public boolean isOwnReader(ImageReader reader) { + throw new UnsupportedOperationException("Not supported yet"); + } + + /** + * Gets an array of strings with names of the ImageWriterSpi classes that + * support the internal metadata representation used by the ImageReader of + * this service provider, or null if there are no such ImageWriters. + * + * @return the array of strings with names of the ImageWriterSpi classes. + */ + public String[] getImageWriterSpiNames() { + throw new UnsupportedOperationException("Not supported yet"); + } +} diff --git a/app/src/main/java/javax/imageio/spi/ImageReaderWriterSpi.java b/app/src/main/java/javax/imageio/spi/ImageReaderWriterSpi.java new file mode 100644 index 000000000..9ca08b5ea --- /dev/null +++ b/app/src/main/java/javax/imageio/spi/ImageReaderWriterSpi.java @@ -0,0 +1,344 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.3 $ + */ + +package javax.imageio.spi; + +import org.apache.harmony.x.imageio.metadata.IIOMetadataUtils; + +import javax.imageio.metadata.IIOMetadataFormat; + +/** + * The ImageReaderWriterSpi class is a superclass for the ImageReaderSpi and + * ImageWriterSpi SPIs. + * + * @since Android 1.0 + */ +public abstract class ImageReaderWriterSpi extends IIOServiceProvider implements + RegisterableService { + + /** + * The names. + */ + protected String[] names; + + /** + * The suffixes. + */ + protected String[] suffixes; + + /** + * The MIME types. + */ + protected String[] MIMETypes; + + /** + * The plug-in class name. + */ + protected String pluginClassName; + + /** + * Whether the reader/writer supports standard stream metadata format. + */ + protected boolean supportsStandardStreamMetadataFormat; + + /** + * The native stream metadata format name. + */ + protected String nativeStreamMetadataFormatName; + + /** + * The native stream metadata format class name. + */ + protected String nativeStreamMetadataFormatClassName; + + /** + * The extra stream metadata format names. + */ + protected String[] extraStreamMetadataFormatNames; + + /** + * The extra stream metadata format class names. + */ + protected String[] extraStreamMetadataFormatClassNames; + + /** + * Whether the reader/writer supports standard image metadata format. + */ + protected boolean supportsStandardImageMetadataFormat; + + /** + * The native image metadata format name. + */ + protected String nativeImageMetadataFormatName; + + /** + * The native image metadata format class name. + */ + protected String nativeImageMetadataFormatClassName; + + /** + * The extra image metadata format names. + */ + protected String[] extraImageMetadataFormatNames; + + /** + * The extra image metadata format class names. + */ + protected String[] extraImageMetadataFormatClassNames; + + /** + * Instantiates a new ImageReaderWriterSpi. + * + * @param vendorName + * the vendor name. + * @param version + * the version. + * @param names + * the format names. + * @param suffixes + * the array of strings representing the file suffixes. + * @param MIMETypes + * the an array of strings representing MIME types. + * @param pluginClassName + * the plug-in class name. + * @param supportsStandardStreamMetadataFormat + * the value indicating if stream metadata can be described by + * standard metadata format. + * @param nativeStreamMetadataFormatName + * the native stream metadata format name, returned by + * getNativeStreamMetadataFormatName. + * @param nativeStreamMetadataFormatClassName + * the native stream metadata format class name, returned by + * getNativeStreamMetadataFormat. + * @param extraStreamMetadataFormatNames + * the extra stream metadata format names, returned by + * getExtraStreamMetadataFormatNames. + * @param extraStreamMetadataFormatClassNames + * the extra stream metadata format class names, returned by + * getStreamMetadataFormat. + * @param supportsStandardImageMetadataFormat + * the value indicating if image metadata can be described by + * standard metadata format. + * @param nativeImageMetadataFormatName + * the native image metadata format name, returned by + * getNativeImageMetadataFormatName. + * @param nativeImageMetadataFormatClassName + * the native image metadata format class name, returned by + * getNativeImageMetadataFormat. + * @param extraImageMetadataFormatNames + * the extra image metadata format names, returned by + * getExtraImageMetadataFormatNames. + * @param extraImageMetadataFormatClassNames + * the extra image metadata format class names, returned by + * getImageMetadataFormat. + */ + public ImageReaderWriterSpi(String vendorName, String version, String[] names, + String[] suffixes, String[] MIMETypes, String pluginClassName, + boolean supportsStandardStreamMetadataFormat, String nativeStreamMetadataFormatName, + String nativeStreamMetadataFormatClassName, String[] extraStreamMetadataFormatNames, + String[] extraStreamMetadataFormatClassNames, + boolean supportsStandardImageMetadataFormat, String nativeImageMetadataFormatName, + String nativeImageMetadataFormatClassName, String[] extraImageMetadataFormatNames, + String[] extraImageMetadataFormatClassNames) { + super(vendorName, version); + + if (names == null || names.length == 0) { + throw new NullPointerException("format names array cannot be NULL or empty"); + } + + if (pluginClassName == null) { + throw new NullPointerException("Plugin class name cannot be NULL"); + } + + // We clone all the arrays to be consistent with the fact that + // some methods of this class must return clones of the arrays + // as it is stated in the spec. + this.names = names.clone(); + this.suffixes = suffixes == null ? null : suffixes.clone(); + this.MIMETypes = MIMETypes == null ? null : MIMETypes.clone(); + this.pluginClassName = pluginClassName; + this.supportsStandardStreamMetadataFormat = supportsStandardStreamMetadataFormat; + this.nativeStreamMetadataFormatName = nativeStreamMetadataFormatName; + this.nativeStreamMetadataFormatClassName = nativeStreamMetadataFormatClassName; + + this.extraStreamMetadataFormatNames = extraStreamMetadataFormatNames == null ? null + : extraStreamMetadataFormatNames.clone(); + + this.extraStreamMetadataFormatClassNames = extraStreamMetadataFormatClassNames == null ? null + : extraStreamMetadataFormatClassNames.clone(); + + this.supportsStandardImageMetadataFormat = supportsStandardImageMetadataFormat; + this.nativeImageMetadataFormatName = nativeImageMetadataFormatName; + this.nativeImageMetadataFormatClassName = nativeImageMetadataFormatClassName; + + this.extraImageMetadataFormatNames = extraImageMetadataFormatNames == null ? null + : extraImageMetadataFormatNames.clone(); + + this.extraImageMetadataFormatClassNames = extraImageMetadataFormatClassNames == null ? null + : extraImageMetadataFormatClassNames.clone(); + } + + /** + * Instantiates a new ImageReaderWriterSpi. + */ + public ImageReaderWriterSpi() { + } + + /** + * Gets an array of strings representing names of the formats that can be + * used by the ImageReader or ImageWriter implementation associated with + * this service provider. + * + * @return the array of supported format names. + */ + public String[] getFormatNames() { + return names.clone(); + } + + /** + * Gets an array of strings representing file suffixes associated with the + * formats that can be used by the ImageReader or ImageWriter implementation + * of this service provider. + * + * @return the array of file suffixes. + */ + public String[] getFileSuffixes() { + return suffixes == null ? null : suffixes.clone(); + } + + /** + * Gets an array of strings with the names of additional formats of the + * image metadata objects produced or consumed by this plug-in. + * + * @return the array of extra image metadata format names. + */ + public String[] getExtraImageMetadataFormatNames() { + return extraImageMetadataFormatNames == null ? null : extraImageMetadataFormatNames.clone(); + } + + /** + * Gets an array of strings with the names of additional formats of the + * stream metadata objects produced or consumed by this plug-in. + * + * @return the array of extra stream metadata format names. + */ + public String[] getExtraStreamMetadataFormatNames() { + return extraStreamMetadataFormatNames == null ? null : extraStreamMetadataFormatNames + .clone(); + } + + /** + * Gets an IIOMetadataFormat object for the specified image metadata format + * name. + * + * @param formatName + * the format name. + * @return the IIOMetadataFormat, or null. + */ + public IIOMetadataFormat getImageMetadataFormat(String formatName) { + return IIOMetadataUtils.instantiateMetadataFormat(formatName, + supportsStandardImageMetadataFormat, nativeImageMetadataFormatName, + nativeImageMetadataFormatClassName, extraImageMetadataFormatNames, + extraImageMetadataFormatClassNames); + } + + /** + * Gets an IIOMetadataFormat object for the specified stream metadata format + * name. + * + * @param formatName + * the format name. + * @return the IIOMetadataFormat, or null. + */ + public IIOMetadataFormat getStreamMetadataFormat(String formatName) { + return IIOMetadataUtils.instantiateMetadataFormat(formatName, + supportsStandardStreamMetadataFormat, nativeStreamMetadataFormatName, + nativeStreamMetadataFormatClassName, extraStreamMetadataFormatNames, + extraStreamMetadataFormatClassNames); + } + + /** + * Gets an array of strings representing the MIME types of the formats that + * are supported by the ImageReader or ImageWriter implementation of this + * service provider. + * + * @return the array MIME types. + */ + public String[] getMIMETypes() { + return MIMETypes == null ? null : MIMETypes.clone(); + } + + /** + * Gets the name of the native image metadata format for this reader/writer, + * which allows for lossless encoding or decoding of the image metadata with + * the format. + * + * @return the string with native image metadata format name, or null. + */ + public String getNativeImageMetadataFormatName() { + return nativeImageMetadataFormatName; + } + + /** + * Gets the name of the native stream metadata format for this + * reader/writer, which allows for lossless encoding or decoding of the + * stream metadata with the format. + * + * @return the string with native stream metadata format name, or null. + */ + public String getNativeStreamMetadataFormatName() { + return nativeStreamMetadataFormatName; + } + + /** + * Gets the class name of the ImageReader or ImageWriter associated with + * this service provider. + * + * @return the class name. + */ + public String getPluginClassName() { + return pluginClassName; + } + + /** + * Checks if the standard metadata format is supported by the getAsTree and + * setFromTree methods for the image metadata objects produced or consumed + * by this reader or writer. + * + * @return true, if standard image metadata format is supported, false + * otherwise. + */ + public boolean isStandardImageMetadataFormatSupported() { + return supportsStandardImageMetadataFormat; + } + + /** + * Checks if the standard metadata format is supported by the getAsTree and + * setFromTree methods for the stream metadata objects produced or consumed + * by this reader or writer. + * + * @return true, if standard stream metadata format is supported, false + * otherwise. + */ + public boolean isStandardStreamMetadataFormatSupported() { + return supportsStandardStreamMetadataFormat; + } +} diff --git a/app/src/main/java/javax/imageio/spi/ImageTranscoderSpi.java b/app/src/main/java/javax/imageio/spi/ImageTranscoderSpi.java new file mode 100644 index 000000000..742af1908 --- /dev/null +++ b/app/src/main/java/javax/imageio/spi/ImageTranscoderSpi.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.3 $ + */ + +package javax.imageio.spi; + +import javax.imageio.ImageTranscoder; + +/** + * The ImageTranscoderSpi class is a service provider interface (SPI) for + * ImageTranscoders. + * + * @since Android 1.0 + */ +public abstract class ImageTranscoderSpi extends IIOServiceProvider implements RegisterableService { + + /** + * Instantiates a new ImageTranscoderSpi. + */ + protected ImageTranscoderSpi() { + } + + /** + * Instantiates a new ImageTranscoderSpi with the specified vendor name and + * version. + * + * @param vendorName + * the vendor name. + * @param version + * the version. + */ + public ImageTranscoderSpi(String vendorName, String version) { + super(vendorName, version); + } + + /** + * Gets the class name of an ImageReaderSpi that produces IIOMetadata + * objects that can be used as input to this transcoder. + * + * @return the class name of an ImageReaderSpi. + */ + public abstract String getReaderServiceProviderName(); + + /** + * Gets the class name of an ImageWriterSpi that produces IIOMetadata + * objects that can be used as input to this transcoder. + * + * @return the class name of an ImageWriterSpi. + */ + public abstract String getWriterServiceProviderName(); + + /** + * Creates an instance of the ImageTranscoder associated with this service + * provider. + * + * @return the ImageTranscoder instance. + */ + public abstract ImageTranscoder createTranscoderInstance(); +} diff --git a/app/src/main/java/javax/imageio/spi/ImageWriterSpi.java b/app/src/main/java/javax/imageio/spi/ImageWriterSpi.java new file mode 100644 index 000000000..bf2545592 --- /dev/null +++ b/app/src/main/java/javax/imageio/spi/ImageWriterSpi.java @@ -0,0 +1,227 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.3 $ + */ + +package javax.imageio.spi; + +import javax.imageio.stream.ImageInputStream; +import javax.imageio.ImageTypeSpecifier; +import javax.imageio.ImageWriter; +import java.awt.image.RenderedImage; +import java.io.IOException; + +/** + * The ImageWriterSpi abstract class is a service provider interface (SPI) for + * ImageWriters. + * + * @since Android 1.0 + */ +public abstract class ImageWriterSpi extends ImageReaderWriterSpi { + + /** + * The STANDARD_OUTPUT_TYPE contains ImageInputStream.class. + */ + public static final Class[] STANDARD_OUTPUT_TYPE = new Class[] { + ImageInputStream.class + }; + + /** + * The output types. + */ + protected Class[] outputTypes; + + /** + * The reader SPI names. + */ + protected String[] readerSpiNames; + + /** + * Instantiates a new ImageWriterSpi. + */ + protected ImageWriterSpi() { + throw new UnsupportedOperationException("Not supported yet"); + } + + /** + * Instantiates a new ImageWriterSpi with the specified parameters. + * + * @param vendorName + * the vendor name. + * @param version + * the version. + * @param names + * the format names. + * @param suffixes + * the array of strings representing the file suffixes. + * @param MIMETypes + * the an array of strings representing MIME types. + * @param pluginClassName + * the plug-in class name. + * @param outputTypes + * the output types. + * @param readerSpiNames + * the array of strings with class names of all associated + * ImageReaders. + * @param supportsStandardStreamMetadataFormat + * the value indicating if stream metadata can be described by + * standard metadata format. + * @param nativeStreamMetadataFormatName + * the native stream metadata format name, returned by + * getNativeStreamMetadataFormatName. + * @param nativeStreamMetadataFormatClassName + * the native stream metadata format class name, returned by + * getNativeStreamMetadataFormat. + * @param extraStreamMetadataFormatNames + * the extra stream metadata format names, returned by + * getExtraStreamMetadataFormatNames. + * @param extraStreamMetadataFormatClassNames + * the extra stream metadata format class names, returned by + * getStreamMetadataFormat. + * @param supportsStandardImageMetadataFormat + * the value indicating if image metadata can be described by + * standard metadata format. + * @param nativeImageMetadataFormatName + * the native image metadata format name, returned by + * getNativeImageMetadataFormatName. + * @param nativeImageMetadataFormatClassName + * the native image metadata format class name, returned by + * getNativeImageMetadataFormat. + * @param extraImageMetadataFormatNames + * the extra image metadata format names, returned by + * getExtraImageMetadataFormatNames. + * @param extraImageMetadataFormatClassNames + * the extra image metadata format class names, returned by + * getImageMetadataFormat. + */ + public ImageWriterSpi(String vendorName, String version, String[] names, String[] suffixes, + String[] MIMETypes, String pluginClassName, Class[] outputTypes, + String[] readerSpiNames, boolean supportsStandardStreamMetadataFormat, + String nativeStreamMetadataFormatName, String nativeStreamMetadataFormatClassName, + String[] extraStreamMetadataFormatNames, String[] extraStreamMetadataFormatClassNames, + boolean supportsStandardImageMetadataFormat, String nativeImageMetadataFormatName, + String nativeImageMetadataFormatClassName, String[] extraImageMetadataFormatNames, + String[] extraImageMetadataFormatClassNames) { + super(vendorName, version, names, suffixes, MIMETypes, pluginClassName, + supportsStandardStreamMetadataFormat, nativeStreamMetadataFormatName, + nativeStreamMetadataFormatClassName, extraStreamMetadataFormatNames, + extraStreamMetadataFormatClassNames, supportsStandardImageMetadataFormat, + nativeImageMetadataFormatName, nativeImageMetadataFormatClassName, + extraImageMetadataFormatNames, extraImageMetadataFormatClassNames); + + if (outputTypes == null || outputTypes.length == 0) { + throw new NullPointerException("output types array cannot be NULL or empty"); + } + + this.outputTypes = outputTypes; + this.readerSpiNames = readerSpiNames; + } + + /** + * Returns true if the format of the writer's output is lossless. The + * default implementation returns true. + * + * @return true, if a format is lossless, false otherwise. + */ + public boolean isFormatLossless() { + return true; + } + + /** + * Gets an array of Class objects whose types can be used as output for this + * writer. + * + * @return the output types. + */ + public Class[] getOutputTypes() { + return outputTypes; + } + + /** + * Checks whether or not the ImageWriter implementation associated with this + * service provider can encode an image with the specified type. + * + * @param type + * the ImageTypeSpecifier. + * @return true, if an image with the specified type can be encoded, false + * otherwise. + */ + public abstract boolean canEncodeImage(ImageTypeSpecifier type); + + /** + * Checks whether or not the ImageWriter implementation associated with this + * service provider can encode the specified RenderedImage. + * + * @param im + * the RenderedImage. + * @return true, if RenderedImage can be encoded, false otherwise. + */ + public boolean canEncodeImage(RenderedImage im) { + return canEncodeImage(ImageTypeSpecifier.createFromRenderedImage(im)); + } + + /** + * Returns an instance of the ImageWriter implementation for this service + * provider. + * + * @return the ImageWriter. + * @throws IOException + * if an I/O exception has occurred. + */ + public ImageWriter createWriterInstance() throws IOException { + return createWriterInstance(null); + } + + /** + * Returns an instance of the ImageWriter implementation for this service + * provider. + * + * @param extension + * the a plug-in specific extension object, or null. + * @return the ImageWriter. + * @throws IOException + * if an I/O exception has occurred. + */ + public abstract ImageWriter createWriterInstance(Object extension) throws IOException; + + /** + * Checks whether or not the specified ImageWriter object is an instance of + * the ImageWriter associated with this service provider or not. + * + * @param writer + * the ImageWriter. + * @return true, if the specified ImageWriter object is an instance of the + * ImageWriter associated with this service provider, false + * otherwise. + */ + public boolean isOwnWriter(ImageWriter writer) { + throw new UnsupportedOperationException("Not supported yet"); + } + + /** + * Gets an array of strings with names of the ImageReaderSpi classes that + * support the internal metadata representation used by the ImageWriter of + * this service provider, or null if there are no such ImageReaders. + * + * @return the array of strings with names of the ImageWriterSpi classes. + */ + public String[] getImageReaderSpiNames() { + return readerSpiNames; + } +} diff --git a/app/src/main/java/javax/imageio/spi/RegisterableService.java b/app/src/main/java/javax/imageio/spi/RegisterableService.java new file mode 100644 index 000000000..ae2f4d39f --- /dev/null +++ b/app/src/main/java/javax/imageio/spi/RegisterableService.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.3 $ + */ + +package javax.imageio.spi; + +/** + * The RegisterableService interface provides service provider objects that can + * be registered by a ServiceRegistry, and notifications that registration and + * deregistration have been performed. + * + * @since Android 1.0 + */ +public interface RegisterableService { + + /** + * This method is called when the object which implements this interface is + * registered to the specified category of the specified registry. + * + * @param registry + * the ServiceRegistry to be registered. + * @param category + * the class representing a category. + */ + void onRegistration(ServiceRegistry registry, Class category); + + /** + * This method is called when the object which implements this interface is + * deregistered to the specified category of the specified registry. + * + * @param registry + * the ServiceRegistry to be registered. + * @param category + * the class representing a category. + */ + void onDeregistration(ServiceRegistry registry, Class category); +} diff --git a/app/src/main/java/javax/imageio/spi/ServiceRegistry.java b/app/src/main/java/javax/imageio/spi/ServiceRegistry.java new file mode 100644 index 000000000..79b02a366 --- /dev/null +++ b/app/src/main/java/javax/imageio/spi/ServiceRegistry.java @@ -0,0 +1,552 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.3 $ + */ + +package javax.imageio.spi; + +import java.util.*; +import java.util.Map.Entry; + +/** + * The ServiceRegistry class provides ability to register, deregister, look up + * and obtain service provider instances (SPIs). A service means a set of + * interfaces and classes, and a service provider is an implementation of a + * service. Service providers can be associated with one or more categories. + * Each category is defined by a class or interface. Only a single instance of a + * each class is allowed to be registered as a category. + * + * @since Android 1.0 + */ +public class ServiceRegistry { + + /** + * The categories. + */ + CategoriesMap categories = new CategoriesMap(this); + + /** + * Instantiates a new ServiceRegistry with the specified categories. + * + * @param categoriesIterator + * an Iterator of Class objects for defining of categories. + */ + public ServiceRegistry(Iterator> categoriesIterator) { + if (null == categoriesIterator) { + throw new IllegalArgumentException("categories iterator should not be NULL"); + } + while (categoriesIterator.hasNext()) { + Class c = categoriesIterator.next(); + categories.addCategory(c); + } + } + + /** + * Looks up and instantiates the available providers of this service using + * the specified class loader. + * + * @param providerClass + * the Class object of the provider to be looked up. + * @param loader + * the class loader to be used. + * @return the iterator of providers objects for this service. + */ + public static Iterator lookupProviders(Class providerClass, ClassLoader loader) { + throw new UnsupportedOperationException("Not supported yet"); + } + + /** + * Looks up and instantiates the available providers of this service using + * the context class loader. + * + * @param providerClass + * the Class object of the provider to be looked up. + * @return the iterator of providers objects for this service. + */ + public static Iterator lookupProviders(Class providerClass) { + return lookupProviders(providerClass, Thread.currentThread().getContextClassLoader()); + } + + /** + * Registers the specified service provider object in the specified + * categories. + * + * @param provider + * the specified provider to be registered. + * @param category + * the category. + * @return true, if no provider of the same class is registered in this + * category, false otherwise. + */ + public boolean registerServiceProvider(T provider, Class category) { + return categories.addProvider(provider, category); + } + + /** + * Registers a list of service providers. + * + * @param providers + * the list of service providers. + */ + public void registerServiceProviders(Iterator providers) { + for (Iterator iterator = providers; iterator.hasNext();) { + categories.addProvider(iterator.next(), null); + } + } + + /** + * Registers the specified service provider object in all categories. + * + * @param provider + * the service provider. + */ + public void registerServiceProvider(Object provider) { + categories.addProvider(provider, null); + } + + /** + * Deregisters the specifies service provider from the specified category. + * + * @param provider + * the service provider to be deregistered. + * @param category + * the specified category. + * @return true, if the provider was already registered in the specified + * category, false otherwise. + */ + public boolean deregisterServiceProvider(T provider, Class category) { + throw new UnsupportedOperationException("Not supported yet"); + } + + /** + * Deregisters the specified service provider from all categories. + * + * @param provider + * the specified service provider. + */ + public void deregisterServiceProvider(Object provider) { + throw new UnsupportedOperationException("Not supported yet"); + } + + /** + * Gets an Iterator of registered service providers in the specified + * category which satisfy the specified Filter. The useOrdering parameter + * indicates whether the iterator will return all of the server provider + * objects in a set order. + * + * @param category + * the specified category. + * @param filter + * the specified filter. + * @param useOrdering + * the flag indicating that providers are ordered in the returned + * Iterator. + * @return the iterator of registered service providers. + */ + @SuppressWarnings("unchecked") + public Iterator getServiceProviders(Class category, Filter filter, boolean useOrdering) { + return new FilteredIterator(filter, (Iterator)categories.getProviders(category, + useOrdering)); + } + + /** + * Gets an Iterator of all registered service providers in the specified + * category. The useOrdering parameter indicates whether the iterator will + * return all of the server provider objects in a set order. + * + * @param category + * the specified category. + * @param useOrdering + * the flag indicating that providers are ordered in the returned + * Iterator. + * @return the Iterator of service providers. + */ + @SuppressWarnings("unchecked") + public Iterator getServiceProviders(Class category, boolean useOrdering) { + return (Iterator)categories.getProviders(category, useOrdering); + } + + /** + * Gets the registered service provider object that has the specified class + * type. + * + * @param providerClass + * the specified provider class. + * @return the service provider object. + */ + public T getServiceProviderByClass(Class providerClass) { + throw new UnsupportedOperationException("Not supported yet"); + } + + /** + * Sets an ordering between two service provider objects within the + * specified category. + * + * @param category + * the specified category. + * @param firstProvider + * the first provider. + * @param secondProvider + * the second provider. + * @return true, if a previously unset order was set. + */ + public boolean setOrdering(Class category, T firstProvider, T secondProvider) { + throw new UnsupportedOperationException("Not supported yet"); + } + + /** + * Unsets an ordering between two service provider objects within the + * specified category. + * + * @param category + * the specified category. + * @param firstProvider + * the first provider. + * @param secondProvider + * the second provider. + * @return true, if a previously unset order was removed. + */ + public boolean unsetOrdering(Class category, T firstProvider, T secondProvider) { + throw new UnsupportedOperationException("Not supported yet"); + } + + /** + * Deregisters all providers from the specified category. + * + * @param category + * the specified category. + */ + public void deregisterAll(Class category) { + throw new UnsupportedOperationException("Not supported yet"); + } + + /** + * Deregister all providers from all categories. + */ + public void deregisterAll() { + throw new UnsupportedOperationException("Not supported yet"); + } + + /** + * Finalizes this object. + * + * @throws Throwable + * if an error occurs during finalization. + */ + @Override + public void finalize() throws Throwable { + // TODO uncomment when deregisterAll is implemented + // deregisterAll(); + } + + /** + * Checks whether the specified provider has been already registered. + * + * @param provider + * the provider to be checked. + * @return true, if the specified provider has been already registered, + * false otherwise. + */ + public boolean contains(Object provider) { + throw new UnsupportedOperationException("Not supported yet"); + } + + /** + * Gets an iterator of Class objects representing the current categories. + * + * @return the Iterator of Class objects. + */ + public Iterator> getCategories() { + return categories.list(); + } + + /** + * The ServiceRegistry.Filter interface is used by + * ServiceRegistry.getServiceProviders to filter providers according to the + * specified criterion. + * + * @since Android 1.0 + */ + public static interface Filter { + + /** + * Returns true if the specified provider satisfies the criterion of + * this Filter. + * + * @param provider + * the provider. + * @return true, if the specified provider satisfies the criterion of + * this Filter, false otherwise. + */ + boolean filter(Object provider); + } + + /** + * The Class CategoriesMap. + */ + private static class CategoriesMap { + + /** + * The categories. + */ + Map, ProvidersMap> categories = new HashMap, ProvidersMap>(); + + /** + * The registry. + */ + ServiceRegistry registry; + + /** + * Instantiates a new categories map. + * + * @param registry + * the registry. + */ + public CategoriesMap(ServiceRegistry registry) { + this.registry = registry; + } + + // -- TODO: useOrdering + /** + * Gets the providers. + * + * @param category + * the category. + * @param useOrdering + * the use ordering. + * @return the providers. + */ + Iterator getProviders(Class category, boolean useOrdering) { + ProvidersMap providers = categories.get(category); + if (null == providers) { + throw new IllegalArgumentException("Unknown category: " + category); + } + return providers.getProviders(useOrdering); + } + + /** + * List. + * + * @return the iterator< class>. + */ + Iterator> list() { + return categories.keySet().iterator(); + } + + /** + * Adds the category. + * + * @param category + * the category. + */ + void addCategory(Class category) { + categories.put(category, new ProvidersMap()); + } + + /** + * Adds a provider to the category. If category is + * null then the provider will be added to all categories + * which the provider is assignable from. + * + * @param provider + * provider to add. + * @param category + * category to add provider to. + * @return true, if there were such provider in some category. + */ + boolean addProvider(Object provider, Class category) { + if (provider == null) { + throw new IllegalArgumentException("provider should be != NULL"); + } + + boolean rt; + if (category == null) { + rt = findAndAdd(provider); + } else { + rt = addToNamed(provider, category); + } + + if (provider instanceof RegisterableService) { + ((RegisterableService)provider).onRegistration(registry, category); + } + + return rt; + } + + /** + * Adds the to named. + * + * @param provider + * the provider. + * @param category + * the category. + * @return true, if successful. + */ + private boolean addToNamed(Object provider, Class category) { + Object obj = categories.get(category); + + if (null == obj) { + throw new IllegalArgumentException("Unknown category: " + category); + } + + return ((ProvidersMap)obj).addProvider(provider); + } + + /** + * Find and add. + * + * @param provider + * the provider. + * @return true, if successful. + */ + private boolean findAndAdd(Object provider) { + boolean rt = false; + for (Entry, ProvidersMap> e : categories.entrySet()) { + if (e.getKey().isAssignableFrom(provider.getClass())) { + rt |= e.getValue().addProvider(provider); + } + } + return rt; + } + } + + /** + * The Class ProvidersMap. + */ + private static class ProvidersMap { + // -- TODO: providers ordering support + + /** + * The providers. + */ + Map, Object> providers = new HashMap, Object>(); + + /** + * Adds the provider. + * + * @param provider + * the provider. + * @return true, if successful. + */ + boolean addProvider(Object provider) { + return providers.put(provider.getClass(), provider) != null; + } + + /** + * Gets the provider classes. + * + * @return the provider classes. + */ + Iterator> getProviderClasses() { + return providers.keySet().iterator(); + } + + // -- TODO ordering + /** + * Gets the providers. + * + * @param userOrdering + * the user ordering. + * @return the providers. + */ + Iterator getProviders(boolean userOrdering) { + return providers.values().iterator(); + } + } + + /** + * The Class FilteredIterator. + */ + private static class FilteredIterator implements Iterator { + + /** + * The filter. + */ + private Filter filter; + + /** + * The backend. + */ + private Iterator backend; + + /** + * The next obj. + */ + private E nextObj; + + /** + * Instantiates a new filtered iterator. + * + * @param filter + * the filter. + * @param backend + * the backend. + */ + public FilteredIterator(Filter filter, Iterator backend) { + this.filter = filter; + this.backend = backend; + findNext(); + } + + /** + * Next. + * + * @return the e. + */ + public E next() { + if (nextObj == null) { + throw new NoSuchElementException(); + } + E tmp = nextObj; + findNext(); + return tmp; + } + + /** + * Checks for next. + * + * @return true, if successful. + */ + public boolean hasNext() { + return nextObj != null; + } + + /** + * Removes the. + */ + public void remove() { + throw new UnsupportedOperationException(); + } + + /** + * Sets nextObj to a next provider matching the criterion given by the + * filter. + */ + private void findNext() { + nextObj = null; + while (backend.hasNext()) { + E o = backend.next(); + if (filter.filter(o)) { + nextObj = o; + return; + } + } + } + } +} diff --git a/app/src/main/java/javax/imageio/spi/package.html b/app/src/main/java/javax/imageio/spi/package.html new file mode 100644 index 000000000..18ceff486 --- /dev/null +++ b/app/src/main/java/javax/imageio/spi/package.html @@ -0,0 +1,8 @@ + + +

    + This package provides several Service Provider Interface (SPI) classes for readers, writers, transcoders and streams to handle images. +

    + @since Android 1.0 + + diff --git a/app/src/main/java/javax/imageio/stream/FileCacheImageInputStream.java b/app/src/main/java/javax/imageio/stream/FileCacheImageInputStream.java new file mode 100644 index 000000000..50f7a7fbc --- /dev/null +++ b/app/src/main/java/javax/imageio/stream/FileCacheImageInputStream.java @@ -0,0 +1,139 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.imageio.stream; + +import java.io.*; + +/** + * The FileCacheImageInputStream class is an implementation of ImageInputStream + * which reads from its InputStream and uses a temporary file as a cache. + * + * @since Android 1.0 + */ +public class FileCacheImageInputStream extends ImageInputStreamImpl { + + /** + * The is. + */ + private InputStream is; + + /** + * The file. + */ + private File file; + + /** + * The raf. + */ + private RandomAccessFile raf; + + /** + * Instantiates a new FileCacheImageInputStream from the specified + * InputStream and using the specified File as its cache directory. + * + * @param stream + * the InputStream for reading. + * @param cacheDir + * the cache directory where the cache file will be created. + * @throws IOException + * if an I/O exception has occurred. + */ + public FileCacheImageInputStream(InputStream stream, File cacheDir) throws IOException { + if (stream == null) { + throw new IllegalArgumentException("stream == null!"); + } + is = stream; + + if (cacheDir == null || cacheDir.isDirectory()) { + file = File.createTempFile(FileCacheImageOutputStream.IIO_TEMP_FILE_PREFIX, null, + cacheDir); + try { + file.deleteOnExit(); + } catch (Throwable unused) {} + } else { + throw new IllegalArgumentException("Not a directory!"); + } + + raf = new RandomAccessFile(file, "rw"); + } + + @Override + public int read() throws IOException { + bitOffset = 0; + + if (streamPos >= raf.length()) { + int b = is.read(); + + if (b < 0) { + return -1; + } + + raf.seek(streamPos++); + raf.write(b); + return b; + } + + raf.seek(streamPos++); + return raf.read(); + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + bitOffset = 0; + + if (streamPos >= raf.length()) { + int nBytes = is.read(b, off, len); + + if (nBytes < 0) { + return -1; + } + + raf.seek(streamPos); + raf.write(b, off, nBytes); + streamPos += nBytes; + return nBytes; + } + + raf.seek(streamPos); + int nBytes = raf.read(b, off, len); + streamPos += nBytes; + return nBytes; + } + + @Override + public boolean isCached() { + return true; + } + + @Override + public boolean isCachedFile() { + return true; + } + + @Override + public boolean isCachedMemory() { + return false; + } + + @Override + public void close() throws IOException { + super.close(); + raf.close(); + file.delete(); + } +} diff --git a/app/src/main/java/javax/imageio/stream/FileCacheImageOutputStream.java b/app/src/main/java/javax/imageio/stream/FileCacheImageOutputStream.java new file mode 100644 index 000000000..994a806d4 --- /dev/null +++ b/app/src/main/java/javax/imageio/stream/FileCacheImageOutputStream.java @@ -0,0 +1,198 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.imageio.stream; + +import java.io.IOException; +import java.io.File; +import java.io.OutputStream; +import java.io.RandomAccessFile; + +/** + * The FileCacheImageOutputStream class is an implementation of + * ImageOutputStream that writes to its OutputStream using a temporary file as a + * cache. + * + * @since Android 1.0 + */ +public class FileCacheImageOutputStream extends ImageOutputStreamImpl { + + /** + * The Constant IIO_TEMP_FILE_PREFIX. + */ + static final String IIO_TEMP_FILE_PREFIX = "iioCache"; + + /** + * The Constant MAX_BUFFER_LEN. + */ + static final int MAX_BUFFER_LEN = 1048575; // 1 MB - is it not too much? + + /** + * The os. + */ + private OutputStream os; + + /** + * The file. + */ + private File file; + + /** + * The raf. + */ + private RandomAccessFile raf; + + /** + * Instantiates a FileCacheImageOutputStream. + * + * @param stream + * the OutputStream for writing. + * @param cacheDir + * the cache directory where the cache file will be created. + * @throws IOException + * if an I/O exception has occurred. + */ + public FileCacheImageOutputStream(OutputStream stream, File cacheDir) throws IOException { + if (stream == null) { + throw new IllegalArgumentException("stream == null!"); + } + os = stream; + + if (cacheDir == null || cacheDir.isDirectory()) { + file = File.createTempFile(IIO_TEMP_FILE_PREFIX, null, cacheDir); + try { + file.deleteOnExit(); + } catch (Throwable unused) {} + } else { + throw new IllegalArgumentException("Not a directory!"); + } + + raf = new RandomAccessFile(file, "rw"); + } + + @Override + public void close() throws IOException { + flushBefore(raf.length()); + super.close(); + raf.close(); + file.delete(); + } + + @Override + public boolean isCached() { + return true; + } + + @Override + public boolean isCachedFile() { + return true; + } + + @Override + public boolean isCachedMemory() { + return false; + } + + @Override + public void write(int b) throws IOException { + flushBits(); // See the flushBits method description + + raf.write(b); + streamPos++; + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + flushBits(); // See the flushBits method description + + raf.write(b, off, len); + streamPos += len; + } + + @Override + public int read() throws IOException { + bitOffset = 0; // Should reset + + int res = raf.read(); + if (res >= 0) { + streamPos++; + } + + return res; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + bitOffset = 0; + + int numRead = raf.read(b, off, len); + if (numRead > 0) { + streamPos += numRead; + } + + return numRead; + } + + @Override + public void flushBefore(long pos) throws IOException { + long readFromPos = flushedPos; + super.flushBefore(pos); + + long bytesToRead = pos - readFromPos; + raf.seek(readFromPos); + + if (bytesToRead < MAX_BUFFER_LEN) { + byte buffer[] = new byte[(int)bytesToRead]; + raf.readFully(buffer); + os.write(buffer); + } else { + byte buffer[] = new byte[MAX_BUFFER_LEN]; + while (bytesToRead > 0) { + int count = (int)Math.min(MAX_BUFFER_LEN, bytesToRead); + raf.readFully(buffer, 0, count); + os.write(buffer, 0, count); + bytesToRead -= count; + } + } + + os.flush(); + + if (pos != streamPos) { + raf.seek(streamPos); // Reset the position + } + } + + @Override + public void seek(long pos) throws IOException { + if (pos < flushedPos) { + throw new IndexOutOfBoundsException(); + } + + raf.seek(pos); + streamPos = raf.getFilePointer(); + bitOffset = 0; + } + + @Override + public long length() { + try { + return raf.length(); + } catch (IOException e) { + return -1L; + } + } +} diff --git a/app/src/main/java/javax/imageio/stream/FileImageInputStream.java b/app/src/main/java/javax/imageio/stream/FileImageInputStream.java new file mode 100644 index 000000000..b9b6002b3 --- /dev/null +++ b/app/src/main/java/javax/imageio/stream/FileImageInputStream.java @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.imageio.stream; + +import java.io.IOException; +import java.io.RandomAccessFile; +import java.io.File; +import java.io.FileNotFoundException; + +/** + * The FileImageInputStream class implements ImageInputStream and obtains its + * input data from a File or RandomAccessFile. + * + * @since Android 1.0 + */ +public class FileImageInputStream extends ImageInputStreamImpl { + + /** + * The raf. + */ + RandomAccessFile raf; + + /** + * Instantiates a new FileImageInputStream from the specified File. + * + * @param f + * the File of input data. + * @throws FileNotFoundException + * if the specified file doesn't exist. + * @throws IOException + * if an I/O exception has occurred. + */ + @SuppressWarnings( { + "DuplicateThrows" + }) + public FileImageInputStream(File f) throws FileNotFoundException, IOException { + if (f == null) { + throw new IllegalArgumentException("f == null!"); + } + + raf = new RandomAccessFile(f, "r"); + } + + /** + * Instantiates a new FileImageInputStream from the specified + * RandomAccessFile. + * + * @param raf + * the RandomAccessFile of input data. + */ + public FileImageInputStream(RandomAccessFile raf) { + if (raf == null) { + throw new IllegalArgumentException("raf == null!"); + } + + this.raf = raf; + } + + @Override + public int read() throws IOException { + bitOffset = 0; + + int res = raf.read(); + if (res != -1) { + streamPos++; + } + return res; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + bitOffset = 0; + + int numRead = raf.read(b, off, len); + if (numRead >= 0) { + streamPos += numRead; + } + + return numRead; + } + + @Override + public long length() { + try { + return raf.length(); + } catch (IOException e) { + return -1L; + } + } + + @Override + public void seek(long pos) throws IOException { + if (pos < getFlushedPosition()) { + throw new IndexOutOfBoundsException(); + } + + raf.seek(pos); + streamPos = raf.getFilePointer(); + bitOffset = 0; + } + + @Override + public void close() throws IOException { + super.close(); + raf.close(); + } +} diff --git a/app/src/main/java/javax/imageio/stream/FileImageOutputStream.java b/app/src/main/java/javax/imageio/stream/FileImageOutputStream.java new file mode 100644 index 000000000..d8d1b559f --- /dev/null +++ b/app/src/main/java/javax/imageio/stream/FileImageOutputStream.java @@ -0,0 +1,134 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.3 $ + */ + +package javax.imageio.stream; + +import java.io.*; + +/** + * The FileImageOutputStream class implements ImageOutputStream and writes the + * output data to a File or RandomAccessFile. + * + * @since Android 1.0 + */ +public class FileImageOutputStream extends ImageOutputStreamImpl { + + /** + * The file. + */ + RandomAccessFile file; + File javaFile; + + /** + * Instantiates a new FileImageOutputStream with the specified File. + * + * @param f + * the output File. + * @throws FileNotFoundException + * if the file not found. + * @throws IOException + * if an I/O exception has occurred. + */ + public FileImageOutputStream(File f) throws FileNotFoundException, IOException { + this(f != null ? new RandomAccessFile(f, "rw") : null); + javaFile = f; + } + + /** + * Instantiates a new FileImageOutputStream with the specified + * RandomAccessFile. + * + * @param raf + * the output RandomAccessFile. + */ + public FileImageOutputStream(RandomAccessFile raf) { + if (raf == null) { + throw new IllegalArgumentException("file should not be NULL"); + } + file = raf; + } + + public File getFile() { + return javaFile; + } + + @Override + public void write(int b) throws IOException { + checkClosed(); + // according to the spec for ImageOutputStreamImpl#flushBits() + flushBits(); + file.write(b); + streamPos++; + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + checkClosed(); + // according to the spec for ImageOutputStreamImpl#flushBits() + flushBits(); + file.write(b, off, len); + streamPos += len; + } + + @Override + public int read() throws IOException { + checkClosed(); + int rt = file.read(); + if (rt != -1) { + streamPos++; + } + return rt; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + checkClosed(); + int rt = file.read(b, off, len); + if (rt != -1) { + streamPos += rt; + } + return rt; + } + + @Override + public long length() { + try { + checkClosed(); + return file.length(); + } catch (IOException e) { + return super.length(); // -1L + } + } + + @Override + public void seek(long pos) throws IOException { + // -- checkClosed() is performed in super.seek() + super.seek(pos); + file.seek(pos); + streamPos = file.getFilePointer(); + } + + @Override + public void close() throws IOException { + super.close(); + file.close(); + } +} diff --git a/app/src/main/java/javax/imageio/stream/IIOByteBuffer.java b/app/src/main/java/javax/imageio/stream/IIOByteBuffer.java new file mode 100644 index 000000000..867d80843 --- /dev/null +++ b/app/src/main/java/javax/imageio/stream/IIOByteBuffer.java @@ -0,0 +1,124 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Sergey I. Salishev + * @version $Revision: 1.2 $ + */ + +package javax.imageio.stream; + +// +// @author Sergey I. Salishev +// @version $Revision: 1.2 $ +// + +/** + * The IIOByteBuffer class represents a byte array with offset and length that + * is used by ImageInputStream for obtaining a sequence of bytes. + * + * @since Android 1.0 + */ +public class IIOByteBuffer { + + /** + * The data. + */ + private byte[] data; + + /** + * The offset. + */ + private int offset; + + /** + * The length. + */ + private int length; + + /** + * Instantiates a new IIOByteBuffer. + * + * @param data + * the byte array. + * @param offset + * the offset in the array. + * @param length + * the length of array. + */ + public IIOByteBuffer(byte[] data, int offset, int length) { + this.data = data; + this.offset = offset; + this.length = length; + } + + /** + * Gets the byte array of this IIOByteBuffer. + * + * @return the byte array. + */ + public byte[] getData() { + return data; + } + + /** + * Gets the length in the array which will be used. + * + * @return the length of the data. + */ + public int getLength() { + return length; + } + + /** + * Gets the offset of this IIOByteBuffer. + * + * @return the offset of this IIOByteBuffer. + */ + public int getOffset() { + return offset; + } + + /** + * Sets the new data array to this IIOByteBuffer object. + * + * @param data + * the new data array. + */ + public void setData(byte[] data) { + this.data = data; + } + + /** + * Sets the length of data which will be used. + * + * @param length + * the new length. + */ + public void setLength(int length) { + this.length = length; + } + + /** + * Sets the offset in the data array of this IIOByteBuffer. + * + * @param offset + * the new offset. + */ + public void setOffset(int offset) { + this.offset = offset; + } +} diff --git a/app/src/main/java/javax/imageio/stream/ImageInputStream.java b/app/src/main/java/javax/imageio/stream/ImageInputStream.java new file mode 100644 index 000000000..3dec5d296 --- /dev/null +++ b/app/src/main/java/javax/imageio/stream/ImageInputStream.java @@ -0,0 +1,502 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.2 $ + */ + +package javax.imageio.stream; + +import java.io.DataInput; +import java.io.IOException; +import java.nio.ByteOrder; + +/** + * The ImageInputStream represents input stream interface that is used by + * ImageReaders. + * + * @since Android 1.0 + */ +public interface ImageInputStream extends DataInput { + + /** + * Sets the specified byte order for reading of data values from this + * stream. + * + * @param byteOrder + * the byte order. + */ + void setByteOrder(ByteOrder byteOrder); + + /** + * Gets the byte order. + * + * @return the byte order. + */ + ByteOrder getByteOrder(); + + /** + * Reads a byte from the stream. + * + * @return the byte of the stream, or -1 for EOF indicating. + * @throws IOException + * if an I/O exception has occurred. + */ + int read() throws IOException; + + /** + * Reads number of bytes which is equal to the specified array's length and + * stores a result to this array. + * + * @param b + * the byte array. + * @return the number of read bytes, or -1 indicated EOF. + * @throws IOException + * if an I/O exception has occurred. + */ + int read(byte[] b) throws IOException; + + /** + * Reads the number of bytes specified by len parameter from the stream and + * stores a result to the specified array with the specified offset. + * + * @param b + * the byte array. + * @param off + * the offset. + * @param len + * the number of bytes to be read. + * @return the number of read bytes, or -1 indicated EOF. + * @throws IOException + * if an I/O exception has occurred. + */ + int read(byte[] b, int off, int len) throws IOException; + + /** + * Reads the number of bytes specified by len parameter from the stream, and + * modifies the specified IIOByteBuffer with the byte array, offset, and + * length. + * + * @param buf + * the IIOByteBuffer. + * @param len + * the number of bytes to be read. + * @throws IOException + * if an I/O exception has occurred. + */ + void readBytes(IIOByteBuffer buf, int len) throws IOException; + + /** + * Reads a byte from the stream and returns a boolean true value if it is + * non zero, false if it is zero. + * + * @return the boolean value for read byte. + * @throws IOException + * if an I/O exception has occurred. + */ + boolean readBoolean() throws IOException; + + /** + * Reads a byte from the stream and returns its value as signed byte. + * + * @return the signed byte value for read byte. + * @throws IOException + * if an I/O exception has occurred. + */ + byte readByte() throws IOException; + + /** + * Reads a byte from the stream and returns its value as an integer. + * + * @return the unsigned byte value for read byte as an integer. + * @throws IOException + * if an I/O exception has occurred. + */ + int readUnsignedByte() throws IOException; + + /** + * Reads 2 bytes from the stream, and returns the result as a short. + * + * @return the signed short value from the stream. + * @throws IOException + * if an I/O exception has occurred. + */ + short readShort() throws IOException; + + /** + * Reads 2 bytes from the stream and returns its value as an unsigned short. + * + * @return a unsigned short value coded in an integer. + * @throws IOException + * if an I/O exception has occurred. + */ + int readUnsignedShort() throws IOException; + + /** + * Reads 2 bytes from the stream and returns their unsigned char value. + * + * @return the unsigned char value. + * @throws IOException + * if an I/O exception has occurred. + */ + char readChar() throws IOException; + + /** + * Reads 4 bytes from the stream, and returns the result as an integer. + * + * @return the signed integer value from the stream. + * @throws IOException + * if an I/O exception has occurred. + */ + int readInt() throws IOException; + + /** + * Reads 4 bytes from the stream and returns its value as long. + * + * @return the unsigned integer value as long. + * @throws IOException + * if an I/O exception has occurred. + */ + long readUnsignedInt() throws IOException; + + /** + * Reads 8 bytes from the stream, and returns the result as a long. + * + * @return the long value from the stream. + * @throws IOException + * if an I/O exception has occurred. + */ + long readLong() throws IOException; + + /** + * Reads 4 bytes from the stream, and returns the result as a float. + * + * @return the float value from the stream. + * @throws IOException + * if an I/O exception has occurred. + */ + float readFloat() throws IOException; + + /** + * Reads 8 bytes from the stream, and returns the result as a double. + * + * @return the double value from the stream. + * @throws IOException + * if an I/O exception has occurred. + */ + double readDouble() throws IOException; + + /** + * Reads a line from the stream. + * + * @return the string contained the line from the stream. + * @throws IOException + * if an I/O exception has occurred. + */ + String readLine() throws IOException; + + /** + * Reads bytes from the stream in a string that has been encoded in a + * modified UTF-8 format. + * + * @return the string read from stream and modified UTF-8 format. + * @throws IOException + * if an I/O exception has occurred. + */ + String readUTF() throws IOException; + + /** + * Reads the specified number of bytes from the stream, and stores the + * result into the specified array starting at the specified index offset. + * + * @param b + * the byte array. + * @param off + * the offset. + * @param len + * the number of bytes to be read. + * @throws IOException + * if an I/O exception has occurred. + */ + void readFully(byte[] b, int off, int len) throws IOException; + + /** + * Reads number of bytes from the stream which is equal to the specified + * array's length, and stores them into this array. + * + * @param b + * the byte array. + * @throws IOException + * if an I/O exception has occurred. + */ + void readFully(byte[] b) throws IOException; + + /** + * Reads the specified number of shorts from the stream, and stores the + * result into the specified array starting at the specified index offset. + * + * @param s + * the short array. + * @param off + * the offset. + * @param len + * the number of shorts to be read. + * @throws IOException + * if an I/O exception has occurred. + */ + void readFully(short[] s, int off, int len) throws IOException; + + /** + * Reads the specified number of chars from the stream, and stores the + * result into the specified array starting at the specified index offset. + * + * @param c + * the char array. + * @param off + * the offset. + * @param len + * the number of chars to be read. + * @throws IOException + * if an I/O exception has occurred. + */ + void readFully(char[] c, int off, int len) throws IOException; + + /** + * Reads the specified number of integer from the stream, and stores the + * result into the specified array starting at the specified index offset. + * + * @param i + * the integer array. + * @param off + * the offset. + * @param len + * the number of integer to be read. + * @throws IOException + * if an I/O exception has occurred. + */ + void readFully(int[] i, int off, int len) throws IOException; + + /** + * Reads the specified number of longs from the stream, and stores the + * result into the specified array starting at the specified index offset. + * + * @param l + * the long array. + * @param off + * the offset. + * @param len + * the number of longs to be read. + * @throws IOException + * if an I/O exception has occurred. + */ + void readFully(long[] l, int off, int len) throws IOException; + + /** + * Reads the specified number of floats from the stream, and stores the + * result into the specified array starting at the specified index offset. + * + * @param f + * the float array. + * @param off + * the offset. + * @param len + * the number of floats to be read. + * @throws IOException + * if an I/O exception has occurred. + */ + void readFully(float[] f, int off, int len) throws IOException; + + /** + * Reads the specified number of doubles from the stream, and stores the + * result into the specified array starting at the specified index offset. + * + * @param d + * the double array. + * @param off + * the offset. + * @param len + * the number of doubles to be read. + * @throws IOException + * if an I/O exception has occurred. + */ + void readFully(double[] d, int off, int len) throws IOException; + + /** + * Gets the stream position. + * + * @return the stream position. + * @throws IOException + * if an I/O exception has occurred. + */ + long getStreamPosition() throws IOException; + + /** + * Gets the bit offset. + * + * @return the bit offset. + * @throws IOException + * if an I/O exception has occurred. + */ + int getBitOffset() throws IOException; + + /** + * Sets the bit offset to an integer between 0 and 7. + * + * @param bitOffset + * the bit offset. + * @throws IOException + * if an I/O exception has occurred. + */ + void setBitOffset(int bitOffset) throws IOException; + + /** + * Reads a bit from the stream and returns the value 0 or 1. + * + * @return the value of single bit: 0 or 1. + * @throws IOException + * if an I/O exception has occurred. + */ + int readBit() throws IOException; + + /** + * Read the specified number of bits and returns their values as long. + * + * @param numBits + * the number of bits to be read. + * @return the bit string as a long. + * @throws IOException + * if an I/O exception has occurred. + */ + long readBits(int numBits) throws IOException; + + /** + * Returns the length of the stream. + * + * @return the length of the stream, or -1 if unknown. + * @throws IOException + * if an I/O exception has occurred. + */ + long length() throws IOException; + + /** + * Skips the specified number of bytes by moving stream position. + * + * @param n + * the number of bytes. + * @return the actual skipped number of bytes. + * @throws IOException + * if an I/O exception has occurred. + */ + int skipBytes(int n) throws IOException; + + /** + * Skips the specified number of bytes by moving stream position. + * + * @param n + * the number of bytes. + * @return the actual skipped number of bytes. + * @throws IOException + * if an I/O exception has occurred. + */ + long skipBytes(long n) throws IOException; + + /** + * Sets the current stream position to the specified location. + * + * @param pos + * a file pointer position. + * @throws IOException + * if an I/O exception has occurred. + */ + void seek(long pos) throws IOException; + + /** + * Marks a position in the stream to be returned to by a subsequent call to + * reset. + */ + void mark(); + + /** + * Returns the file pointer to its previous position. + * + * @throws IOException + * if an I/O exception has occurred. + */ + void reset() throws IOException; + + /** + * Flushes the initial position in this stream prior to the specified stream + * position. + * + * @param pos + * the position. + * @throws IOException + * if an I/O exception has occurred. + */ + void flushBefore(long pos) throws IOException; + + /** + * Flushes the initial position in this stream prior to the current stream + * position. + * + * @throws IOException + * if an I/O exception has occurred. + */ + void flush() throws IOException; + + /** + * Gets the flushed position. + * + * @return the flushed position. + */ + long getFlushedPosition(); + + /** + * Returns true if this ImageInputStream caches data in order to allow + * seeking backwards. + * + * @return true, if this ImageInputStream caches data in order to allow + * seeking backwards, false otherwise. + */ + boolean isCached(); + + /** + * Returns true if this ImageInputStream caches data in order to allow + * seeking backwards, and keeps it in memory. + * + * @return true, if this ImageInputStream caches data in order to allow + * seeking backwards, and keeps it in memory. + */ + boolean isCachedMemory(); + + /** + * Returns true if this ImageInputStream caches data in order to allow + * seeking backwards, and keeps it in a temporary file. + * + * @return true, if this ImageInputStream caches data in order to allow + * seeking backwards, and keeps it in a temporary file. + */ + boolean isCachedFile(); + + /** + * Closes this stream. + * + * @throws IOException + * if an I/O exception has occurred. + */ + void close() throws IOException; +} diff --git a/app/src/main/java/javax/imageio/stream/ImageInputStreamImpl.java b/app/src/main/java/javax/imageio/stream/ImageInputStreamImpl.java new file mode 100644 index 000000000..fe55e9fd2 --- /dev/null +++ b/app/src/main/java/javax/imageio/stream/ImageInputStreamImpl.java @@ -0,0 +1,418 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.3 $ + */ + +package javax.imageio.stream; + +import java.io.EOFException; +import java.io.IOException; +import java.nio.ByteOrder; + +/** + * The ImageInputStreamImpl abstract class implements the ImageInputStream + * interface. + * + * @since Android 1.0 + */ +public abstract class ImageInputStreamImpl implements ImageInputStream { + + /** + * The byte order. + */ + protected ByteOrder byteOrder = ByteOrder.BIG_ENDIAN; + + /** + * The stream position. + */ + protected long streamPos = 0; + + /** + * The flushed position. + */ + protected long flushedPos = 0; + + /** + * The bit offset. + */ + protected int bitOffset = 0; + + /** + * The closed. + */ + private boolean closed = false; + + /** + * The position stack. + */ + private final PositionStack posStack = new PositionStack(); + + /** + * Instantiates a new ImageInputStreamImpl. + */ + public ImageInputStreamImpl() { + } + + /** + * Check if the stream is closed and if true, throws an IOException. + * + * @throws IOException + * if the stream is closed. + */ + protected final void checkClosed() throws IOException { + if (closed) { + throw new IOException("stream is closed"); + } + } + + public void setByteOrder(ByteOrder byteOrder) { + this.byteOrder = byteOrder; + } + + public ByteOrder getByteOrder() { + return byteOrder; + } + + public abstract int read() throws IOException; + + public int read(byte[] b) throws IOException { + return read(b, 0, b.length); + } + + public abstract int read(byte[] b, int off, int len) throws IOException; + + public void readBytes(IIOByteBuffer buf, int len) throws IOException { + if (buf == null) { + throw new NullPointerException("buffer is NULL"); + } + + byte[] b = new byte[len]; + len = read(b, 0, b.length); + + buf.setData(b); + buf.setOffset(0); + buf.setLength(len); + } + + public boolean readBoolean() throws IOException { + int b = read(); + if (b < 0) { + throw new EOFException("EOF reached"); + } + return b != 0; + } + + public byte readByte() throws IOException { + int b = read(); + if (b < 0) { + throw new EOFException("EOF reached"); + } + return (byte)b; + } + + public int readUnsignedByte() throws IOException { + int b = read(); + if (b < 0) { + throw new EOFException("EOF reached"); + } + return b; + } + + public short readShort() throws IOException { + int b1 = read(); + int b2 = read(); + + if (b1 < 0 || b2 < 0) { + throw new EOFException("EOF reached"); + } + + return byteOrder == ByteOrder.BIG_ENDIAN ? (short)((b1 << 8) | (b2 & 0xff)) + : (short)((b2 << 8) | (b1 & 0xff)); + } + + public int readUnsignedShort() throws IOException { + // -- TODO implement + throw new UnsupportedOperationException("Not implemented yet"); + } + + public char readChar() throws IOException { + // -- TODO implement + throw new UnsupportedOperationException("Not implemented yet"); + } + + public int readInt() throws IOException { + // -- TODO implement + throw new UnsupportedOperationException("Not implemented yet"); + } + + public long readUnsignedInt() throws IOException { + // -- TODO implement + throw new UnsupportedOperationException("Not implemented yet"); + } + + public long readLong() throws IOException { + // -- TODO implement + throw new UnsupportedOperationException("Not implemented yet"); + } + + public float readFloat() throws IOException { + // -- TODO implement + throw new UnsupportedOperationException("Not implemented yet"); + } + + public double readDouble() throws IOException { + // -- TODO implement + throw new UnsupportedOperationException("Not implemented yet"); + } + + public String readLine() throws IOException { + // -- TODO implement + throw new UnsupportedOperationException("Not implemented yet"); + } + + public String readUTF() throws IOException { + // -- TODO implement + throw new UnsupportedOperationException("Not implemented yet"); + } + + public void readFully(byte[] b, int off, int len) throws IOException { + // -- TODO implement + throw new UnsupportedOperationException("Not implemented yet"); + } + + public void readFully(byte[] b) throws IOException { + readFully(b, 0, b.length); + } + + public void readFully(short[] s, int off, int len) throws IOException { + // -- TODO implement + throw new UnsupportedOperationException("Not implemented yet"); + } + + public void readFully(char[] c, int off, int len) throws IOException { + // -- TODO implement + throw new UnsupportedOperationException("Not implemented yet"); + } + + public void readFully(int[] i, int off, int len) throws IOException { + // -- TODO implement + throw new UnsupportedOperationException("Not implemented yet"); + } + + public void readFully(long[] l, int off, int len) throws IOException { + // -- TODO implement + throw new UnsupportedOperationException("Not implemented yet"); + } + + public void readFully(float[] f, int off, int len) throws IOException { + // -- TODO implement + throw new UnsupportedOperationException("Not implemented yet"); + } + + public void readFully(double[] d, int off, int len) throws IOException { + // -- TODO implement + throw new UnsupportedOperationException("Not implemented yet"); + } + + public long getStreamPosition() throws IOException { + checkClosed(); + return streamPos; + } + + public int getBitOffset() throws IOException { + checkClosed(); + return bitOffset; + } + + public void setBitOffset(int bitOffset) throws IOException { + checkClosed(); + this.bitOffset = bitOffset; + } + + public int readBit() throws IOException { + // -- TODO implement + throw new UnsupportedOperationException("Not implemented yet"); + } + + public long readBits(int numBits) throws IOException { + // -- TODO implement + throw new UnsupportedOperationException("Not implemented yet"); + } + + public long length() { + return -1L; + } + + public int skipBytes(int n) throws IOException { + // -- TODO implement + throw new UnsupportedOperationException("Not implemented yet"); + } + + public long skipBytes(long n) throws IOException { + // -- TODO implement + throw new UnsupportedOperationException("Not implemented yet"); + } + + public void seek(long pos) throws IOException { + checkClosed(); + if (pos < getFlushedPosition()) { + throw new IllegalArgumentException("trying to seek before flushed pos"); + } + bitOffset = 0; + streamPos = pos; + } + + public void mark() { + try { + posStack.push(getStreamPosition()); + } catch (IOException e) { + e.printStackTrace(); + throw new RuntimeException("Stream marking error"); + } + } + + public void reset() throws IOException { + // -- TODO bit pos + if (!posStack.isEmpty()) { + long p = posStack.pop(); + if (p < flushedPos) { + throw new IOException("marked position lies in the flushed portion of the stream"); + } + seek(p); + } + } + + public void flushBefore(long pos) throws IOException { + if (pos > getStreamPosition()) { + throw new IndexOutOfBoundsException("Trying to flush outside of current position"); + } + if (pos < flushedPos) { + throw new IndexOutOfBoundsException("Trying to flush within already flushed portion"); + } + flushedPos = pos; + // -- TODO implement + } + + public void flush() throws IOException { + flushBefore(getStreamPosition()); + } + + public long getFlushedPosition() { + return flushedPos; + } + + public boolean isCached() { + return false; // def + } + + public boolean isCachedMemory() { + return false; // def + } + + public boolean isCachedFile() { + return false; // def + } + + public void close() throws IOException { + checkClosed(); + closed = true; + + } + + /** + * Finalizes this object. + * + * @throws Throwable + * if an error occurs. + */ + @Override + protected void finalize() throws Throwable { + if (!closed) { + try { + close(); + } finally { + super.finalize(); + } + } + } + + /** + * The Class PositionStack. + */ + private static class PositionStack { + + /** + * The Constant SIZE. + */ + private static final int SIZE = 10; + + /** + * The values. + */ + private long[] values = new long[SIZE]; + + /** + * The pos. + */ + private int pos = 0; + + /** + * Push. + * + * @param v + * the v. + */ + void push(long v) { + if (pos >= values.length) { + ensure(pos + 1); + } + values[pos++] = v; + } + + /** + * Pop. + * + * @return the long. + */ + long pop() { + return values[--pos]; + } + + /** + * Checks if is empty. + * + * @return true, if is empty. + */ + boolean isEmpty() { + return pos == 0; + } + + /** + * Ensure. + * + * @param size + * the size. + */ + private void ensure(int size) { + long[] arr = new long[Math.max(2 * values.length, size)]; + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(values, 0, arr, 0, values.length); + values = arr; + } + } +} diff --git a/app/src/main/java/javax/imageio/stream/ImageOutputStream.java b/app/src/main/java/javax/imageio/stream/ImageOutputStream.java new file mode 100644 index 000000000..28ec93277 --- /dev/null +++ b/app/src/main/java/javax/imageio/stream/ImageOutputStream.java @@ -0,0 +1,307 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.2 $ + */ + +package javax.imageio.stream; + +import java.io.DataOutput; +import java.io.IOException; + +/** + * The ImageOutputStream represents output stream interface that is used by + * ImageWriters. + * + * @since Android 1.0 + */ +public interface ImageOutputStream extends DataOutput, ImageInputStream { + + /** + * Writes a single byte to the stream at the current position. + * + * @param b + * the integer value, of which the 8 lowest bits will be written. + * @throws IOException + * if an I/O exception has occurred. + */ + void write(int b) throws IOException; + + /** + * Writes the bytes array to the stream. + * + * @param b + * the byte array to be written. + * @throws IOException + * if an I/O exception has occurred. + */ + void write(byte[] b) throws IOException; + + /** + * Writes a number of bytes from the specified byte array beginning from the + * specified offset. + * + * @param b + * the byte array. + * @param off + * the offset. + * @param len + * the number of bytes to be written. + * @throws IOException + * if an I/O exception has occurred. + */ + void write(byte[] b, int off, int len) throws IOException; + + /** + * Writes the specified boolean value to the stream, 1 if it is true, 0 if + * it is false. + * + * @param b + * the boolean value to be written. + * @throws IOException + * if an I/O exception has occurred. + */ + void writeBoolean(boolean b) throws IOException; + + /** + * Writes the 8 lowest bits of the specified integer value to the stream. + * + * @param b + * the specified integer value. + * @throws IOException + * if an I/O exception has occurred. + */ + void writeByte(int b) throws IOException; + + /** + * Writes a short value to the output stream. + * + * @param v + * the short value to be written. + * @throws IOException + * if an I/O exception has occurred. + */ + void writeShort(int v) throws IOException; + + /** + * Writes the 16 lowest bits of the specified integer value to the stream. + * + * @param v + * the specified integer value. + * @throws IOException + * if an I/O exception has occurred. + */ + void writeChar(int v) throws IOException; + + /** + * Writes an integer value to the output stream. + * + * @param v + * the integer value to be written. + * @throws IOException + * if an I/O exception has occurred. + */ + void writeInt(int v) throws IOException; + + /** + * Write long. + * + * @param v + * the long value. + * @throws IOException + * if an I/O exception has occurred. + */ + void writeLong(long v) throws IOException; + + /** + * Writes a float value to the output stream. + * + * @param v + * the float which contains value to be written. + * @throws IOException + * if an I/O exception has occurred. + */ + void writeFloat(float v) throws IOException; + + /** + * Writes a double value to the output stream. + * + * @param v + * the double which contains value to be written. + * @throws IOException + * if an I/O exception has occurred. + */ + void writeDouble(double v) throws IOException; + + /** + * Writes the specified string to the stream. + * + * @param s + * the string to be written. + * @throws IOException + * if an I/O exception has occurred. + */ + void writeBytes(String s) throws IOException; + + /** + * Writes the specified String to the output stream. + * + * @param s + * the String to be written. + * @throws IOException + * if an I/O exception has occurred. + */ + void writeChars(String s) throws IOException; + + /** + * Writes 2 bytes to the output stream in the modified UTF-8 representation + * of every character of the specified string. + * + * @param s + * the specified string to be written. + * @throws IOException + * if an I/O exception has occurred. + */ + void writeUTF(String s) throws IOException; + + /** + * Flushes the initial position in this stream prior to the specified stream + * position. + * + * @param pos + * the position. + * @throws IOException + * if an I/O exception has occurred. + */ + void flushBefore(long pos) throws IOException; + + /** + * Writes a len number of short values from the specified array to the + * stream. + * + * @param s + * the shorts array to be written. + * @param off + * the offset in the char array. + * @param len + * the length of chars to be written. + * @throws IOException + * if an I/O exception has occurred. + */ + void writeShorts(short[] s, int off, int len) throws IOException; + + /** + * Writes a len number of chars to the stream. + * + * @param c + * the char array to be written. + * @param off + * the offset in the char array. + * @param len + * the length of chars to be written. + * @throws IOException + * if an I/O exception has occurred. + */ + void writeChars(char[] c, int off, int len) throws IOException; + + /** + * Writes a len number of integer values from the specified array to the + * stream. + * + * @param i + * the integer array to be written. + * @param off + * the offset in the char array. + * @param len + * the length of chars to be written. + * @throws IOException + * if an I/O exception has occurred. + */ + void writeInts(int[] i, int off, int len) throws IOException; + + /** + * Writes a len number of long values from the specified array to the + * stream. + * + * @param l + * the long array to be written. + * @param off + * the offset in the char array. + * @param len + * the length of chars to be written. + * @throws IOException + * if an I/O exception has occurred. + */ + void writeLongs(long[] l, int off, int len) throws IOException; + + /** + * Writes a len number of float values from the specified array to the + * stream. + * + * @param f + * the float array to be written. + * @param off + * the offset in the char array. + * @param len + * the length of chars to be written. + * @throws IOException + * if an I/O exception has occurred. + */ + void writeFloats(float[] f, int off, int len) throws IOException; + + /** + * Writes a len number of double values from the specified array to the + * stream. + * + * @param d + * the double array to be written. + * @param off + * the offset in the char array. + * @param len + * the length of chars to be written. + * @throws IOException + * if an I/O exception has occurred. + */ + void writeDoubles(double[] d, int off, int len) throws IOException; + + /** + * Writes a single bit at the current position. + * + * @param bit + * the integer whose least significant bit is to be written to + * the stream. + * @throws IOException + * if an I/O exception has occurred. + */ + void writeBit(int bit) throws IOException; + + /** + * Writes a sequence of bits beginning from the current position. + * + * @param bits + * the long value containing the bits to be written, starting + * with the bit in position numBits - 1 down to the least + * significant bit. + * @param numBits + * the number of significant bit, it can be between 0 and 64. + * @throws IOException + * if an I/O exception has occurred. + */ + void writeBits(long bits, int numBits) throws IOException; + +} diff --git a/app/src/main/java/javax/imageio/stream/ImageOutputStreamImpl.java b/app/src/main/java/javax/imageio/stream/ImageOutputStreamImpl.java new file mode 100644 index 000000000..99613fcb2 --- /dev/null +++ b/app/src/main/java/javax/imageio/stream/ImageOutputStreamImpl.java @@ -0,0 +1,175 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.3 $ + */ + +package javax.imageio.stream; + +import java.io.IOException; +import java.nio.ByteOrder; + +/* + * @author Rustem V. Rafikov + * @version $Revision: 1.3 $ + */ + +/** + * The ImageOutputStreamImpl abstract class implements the ImageOutputStream + * interface. + * + * @since Android 1.0 + */ +public abstract class ImageOutputStreamImpl extends ImageInputStreamImpl implements + ImageOutputStream { + + /** + * Instantiates a new ImageOutputStreamImpl. + */ + public ImageOutputStreamImpl() { + } + + public abstract void write(int b) throws IOException; + + public void write(byte[] b) throws IOException { + write(b, 0, b.length); + } + + public abstract void write(byte[] b, int off, int len) throws IOException; + + public void writeBoolean(boolean v) throws IOException { + write(v ? 1 : 0); + } + + public void writeByte(int v) throws IOException { + write(v); + } + + public void writeShort(int v) throws IOException { + if (byteOrder == ByteOrder.BIG_ENDIAN) { + + } else { + + } + // -- TODO implement + throw new UnsupportedOperationException("Not implemented yet"); + } + + public void writeChar(int v) throws IOException { + writeShort(v); + } + + public void writeInt(int v) throws IOException { + if (byteOrder == ByteOrder.BIG_ENDIAN) { + + } else { + + } + // -- TODO implement + throw new UnsupportedOperationException("Not implemented yet"); + } + + public void writeLong(long v) throws IOException { + if (byteOrder == ByteOrder.BIG_ENDIAN) { + + } else { + + } + // -- TODO implement + throw new UnsupportedOperationException("Not implemented yet"); + } + + public void writeFloat(float v) throws IOException { + writeInt(Float.floatToIntBits(v)); + } + + public void writeDouble(double v) throws IOException { + writeLong(Double.doubleToLongBits(v)); + } + + public void writeBytes(String s) throws IOException { + write(s.getBytes()); + } + + public void writeChars(String s) throws IOException { + char[] chs = s.toCharArray(); + writeChars(chs, 0, chs.length); + } + + public void writeUTF(String s) throws IOException { + // -- TODO implement + // throw new UnsupportedOperationException("Not implemented yet"); + writeChars(s); + } + + public void writeShorts(short[] s, int off, int len) throws IOException { + // -- TODO implement + throw new UnsupportedOperationException("Not implemented yet"); + } + + public void writeChars(char[] c, int off, int len) throws IOException { + // -- TODO implement + throw new UnsupportedOperationException("Not implemented yet"); + } + + public void writeInts(int[] i, int off, int len) throws IOException { + // -- TODO implement + throw new UnsupportedOperationException("Not implemented yet"); + } + + public void writeLongs(long[] l, int off, int len) throws IOException { + // -- TODO implement + throw new UnsupportedOperationException("Not implemented yet"); + } + + public void writeFloats(float[] f, int off, int len) throws IOException { + // -- TODO implement + throw new UnsupportedOperationException("Not implemented yet"); + } + + public void writeDoubles(double[] d, int off, int len) throws IOException { + // -- TODO implement + throw new UnsupportedOperationException("Not implemented yet"); + } + + public void writeBit(int bit) throws IOException { + // -- TODO implement + throw new UnsupportedOperationException("Not implemented yet"); + } + + public void writeBits(long bits, int numBits) throws IOException { + // -- TODO implement + throw new UnsupportedOperationException("Not implemented yet"); + } + + /** + * Flushes the bits. This method should be called in the write methods by + * subclasses. + * + * @throws IOException + * if an I/O exception has occurred. + */ + protected final void flushBits() throws IOException { + if (bitOffset == 0) { + return; + } + + // -- TODO implement + throw new UnsupportedOperationException("Not implemented yet"); + } +} diff --git a/app/src/main/java/javax/imageio/stream/MemoryCacheImageInputStream.java b/app/src/main/java/javax/imageio/stream/MemoryCacheImageInputStream.java new file mode 100644 index 000000000..d7fc79139 --- /dev/null +++ b/app/src/main/java/javax/imageio/stream/MemoryCacheImageInputStream.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.imageio.stream; + +import org.apache.harmony.x.imageio.stream.RandomAccessMemoryCache; + +import java.io.IOException; +import java.io.InputStream; + +/** + * The MemoryCacheImageInputStream class implements ImageInputStream using a + * memory buffer for caching the data. + * + * @since Android 1.0 + */ +public class MemoryCacheImageInputStream extends ImageInputStreamImpl { + + /** + * The is. + */ + private InputStream is; + + /** + * The ramc. + */ + private RandomAccessMemoryCache ramc = new RandomAccessMemoryCache(); + + /** + * Instantiates a new MemoryCacheImageInputStream which reads from the + * specified InputStream. + * + * @param stream + * the InputStream to be read. + */ + public MemoryCacheImageInputStream(InputStream stream) { + if (stream == null) { + throw new IllegalArgumentException("stream == null!"); + } + is = stream; + } + + @Override + public int read() throws IOException { + bitOffset = 0; + + if (streamPos >= ramc.length()) { + int count = (int)(streamPos - ramc.length() + 1); + int bytesAppended = ramc.appendData(is, count); + + if (bytesAppended < count) { + return -1; + } + } + + int res = ramc.getData(streamPos); + if (res >= 0) { + streamPos++; + } + return res; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + bitOffset = 0; + + if (streamPos >= ramc.length()) { + int count = (int)(streamPos - ramc.length() + len); + ramc.appendData(is, count); + } + + int res = ramc.getData(b, off, len, streamPos); + if (res > 0) { + streamPos += res; + } + return res; + } + + @Override + public boolean isCached() { + return true; + } + + @Override + public boolean isCachedFile() { + return false; + } + + @Override + public boolean isCachedMemory() { + return true; + } + + @Override + public void close() throws IOException { + super.close(); + ramc.close(); + } + + @Override + public void flushBefore(long pos) throws IOException { + super.flushBefore(pos); + ramc.freeBefore(getFlushedPosition()); + } +} diff --git a/app/src/main/java/javax/imageio/stream/MemoryCacheImageOutputStream.java b/app/src/main/java/javax/imageio/stream/MemoryCacheImageOutputStream.java new file mode 100644 index 000000000..1df40a342 --- /dev/null +++ b/app/src/main/java/javax/imageio/stream/MemoryCacheImageOutputStream.java @@ -0,0 +1,135 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.imageio.stream; + +import org.apache.harmony.x.imageio.stream.RandomAccessMemoryCache; + +import java.io.OutputStream; +import java.io.IOException; + +/** + * The MemoryCacheImageOutputStream class implements ImageOutputStream using a + * memory buffer for caching the data. + * + * @since Android 1.0 + */ +public class MemoryCacheImageOutputStream extends ImageOutputStreamImpl { + + /** + * The os. + */ + OutputStream os; + + /** + * The ramc. + */ + RandomAccessMemoryCache ramc = new RandomAccessMemoryCache(); + + /** + * Instantiates a new MemoryCacheImageOutputStream which writes to the + * specified OutputStream. + * + * @param stream + * the OutputStream. + */ + public MemoryCacheImageOutputStream(OutputStream stream) { + if (stream == null) { + throw new IllegalArgumentException("stream == null!"); + } + os = stream; + } + + @Override + public void write(int b) throws IOException { + flushBits(); // See the flushBits method description + + ramc.putData(b, streamPos); + streamPos++; + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + flushBits(); // See the flushBits method description + + ramc.putData(b, off, len, streamPos); + streamPos += len; + } + + @Override + public int read() throws IOException { + bitOffset = 0; + + int res = ramc.getData(streamPos); + if (res >= 0) { + streamPos++; + } + return res; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + bitOffset = 0; + + int res = ramc.getData(b, off, len, streamPos); + if (res > 0) { + streamPos += res; + } + return res; + } + + @Override + public long length() { + return ramc.length(); + } + + @Override + public boolean isCached() { + return true; + } + + @Override + public boolean isCachedMemory() { + return true; + } + + @Override + public boolean isCachedFile() { + return false; + } + + @Override + public void close() throws IOException { + flushBefore(length()); + super.close(); + ramc.close(); + } + + @Override + public void flushBefore(long pos) throws IOException { + long flushedPosition = getFlushedPosition(); + super.flushBefore(pos); + + long newFlushedPosition = getFlushedPosition(); + int nBytes = (int)(newFlushedPosition - flushedPosition); + + ramc.getData(os, nBytes, flushedPosition); + ramc.freeBefore(newFlushedPosition); + + os.flush(); + } +} diff --git a/app/src/main/java/javax/imageio/stream/package.html b/app/src/main/java/javax/imageio/stream/package.html new file mode 100644 index 000000000..6cf53c3c0 --- /dev/null +++ b/app/src/main/java/javax/imageio/stream/package.html @@ -0,0 +1,8 @@ + + +

    + This package contains classes and interfaces for handling images with low-level I/O operations. +

    + @since Android 1.0 + + diff --git a/app/src/main/java/javax/sound/midi/MetaMessage.java b/app/src/main/java/javax/sound/midi/MetaMessage.java index 43244fc0f..425604745 100644 --- a/app/src/main/java/javax/sound/midi/MetaMessage.java +++ b/app/src/main/java/javax/sound/midi/MetaMessage.java @@ -100,7 +100,7 @@ public class MetaMessage extends MidiMessage { // Write data if (newData.length > 0) { - System.arraycopy(newData, 0, this.data, headerLength, newData.length); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(newData, 0, this.data, headerLength, newData.length); } } @@ -128,7 +128,7 @@ public class MetaMessage extends MidiMessage { } final byte[] returnedArray = new byte[dataLength]; - System.arraycopy(data, data.length - dataLength, returnedArray, 0, dataLength); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(data, data.length - dataLength, returnedArray, 0, dataLength); return returnedArray; } @@ -140,7 +140,7 @@ public class MetaMessage extends MidiMessage { return new MetaMessage(emptyData); } final byte[] result = new byte[data.length]; - System.arraycopy(data, 0, result, 0, data.length); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(data, 0, result, 0, data.length); return new MetaMessage(result); } diff --git a/app/src/main/java/javax/sound/midi/MidiMessage.java b/app/src/main/java/javax/sound/midi/MidiMessage.java index 53da81a84..6c8a75b19 100644 --- a/app/src/main/java/javax/sound/midi/MidiMessage.java +++ b/app/src/main/java/javax/sound/midi/MidiMessage.java @@ -45,7 +45,7 @@ public abstract class MidiMessage implements Cloneable { } this.length = data.length; - System.arraycopy(data, 0, this.data, 0, data.length); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(data, 0, this.data, 0, data.length); } } @@ -61,7 +61,7 @@ public abstract class MidiMessage implements Cloneable { } final byte[] resultArray = new byte[data.length]; - System.arraycopy(data, 0, resultArray, 0, data.length); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(data, 0, resultArray, 0, data.length); return resultArray; } diff --git a/app/src/main/java/javax/sound/midi/ShortMessage.java b/app/src/main/java/javax/sound/midi/ShortMessage.java index 4db108187..654cf7846 100644 --- a/app/src/main/java/javax/sound/midi/ShortMessage.java +++ b/app/src/main/java/javax/sound/midi/ShortMessage.java @@ -199,7 +199,7 @@ public class ShortMessage extends MidiMessage { @Override public Object clone() { final byte[] result = new byte[data.length]; - System.arraycopy(data, 0, result, 0, result.length); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(data, 0, result, 0, result.length); return new ShortMessage(result); } diff --git a/app/src/main/java/javax/sound/midi/SysexMessage.java b/app/src/main/java/javax/sound/midi/SysexMessage.java index cdee8f062..93a074dff 100644 --- a/app/src/main/java/javax/sound/midi/SysexMessage.java +++ b/app/src/main/java/javax/sound/midi/SysexMessage.java @@ -83,7 +83,7 @@ public class SysexMessage extends MidiMessage { this.data[0] = (byte) (status & 0xff); if (data.length > 0) { - System.arraycopy(data, 0, this.data, 1, data.length); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(data, 0, this.data, 1, data.length); } } @@ -95,7 +95,7 @@ public class SysexMessage extends MidiMessage { @NonNull public byte[] getData() { final byte[] result = new byte[data.length]; - System.arraycopy(data, 0, result, 0, result.length); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(data, 0, result, 0, result.length); return result; } diff --git a/app/src/main/java/javax/swing/JOptionPane.java b/app/src/main/java/javax/swing/JOptionPane.java index 7e5672aa8..1716f697d 100644 --- a/app/src/main/java/javax/swing/JOptionPane.java +++ b/app/src/main/java/javax/swing/JOptionPane.java @@ -8,9 +8,10 @@ import android.content.*; public class JOptionPane { + private static boolean isOk; - public static void showMessageDialog(Component parentComponent, final Object title, final String message, int messageType) { - Log.w("JOptionPane", "[" + message + "] " + title.toString()); + public static void showMessageDialog(Component parentComponent, final Object message, final String title, int messageType) { + Log.w("JOptionPane", "[" + title + "] " + message.toString()); isOk = false; final Activity act = ModdingKit.getCurrentActivity(); @@ -20,8 +21,8 @@ public class JOptionPane public void run() { AlertDialog.Builder dialog = new AlertDialog.Builder(act); - dialog.setTitle(title.toString()); - dialog.setMessage(message); + dialog.setTitle(title); + dialog.setMessage(message.toString()); dialog.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener(){ @Override diff --git a/app/src/main/java/net/kdt/pojavlaunch/AndroidLWJGLKeycode.java b/app/src/main/java/net/kdt/pojavlaunch/AndroidLWJGLKeycode.java index 04717c1ff..cf621d269 100644 --- a/app/src/main/java/net/kdt/pojavlaunch/AndroidLWJGLKeycode.java +++ b/app/src/main/java/net/kdt/pojavlaunch/AndroidLWJGLKeycode.java @@ -8,9 +8,13 @@ import org.lwjgl.opengl.*; public class AndroidLWJGLKeycode { public static boolean isBackspaceAfterChar; - private static final Map androidToLwjglMap; + private static final ArrayMap androidToLwjglMap; + private static String[] androidKeyNameArray; static { + // Mapping Android Key to LWJGL Key from scratch androidToLwjglMap = new ArrayMap(); + + // 0-9 keys androidToLwjglMap.put(KeyEvent.KEYCODE_0, Keyboard.KEY_0); androidToLwjglMap.put(KeyEvent.KEYCODE_1, Keyboard.KEY_1); androidToLwjglMap.put(KeyEvent.KEYCODE_2, Keyboard.KEY_2); @@ -21,6 +25,8 @@ public class AndroidLWJGLKeycode { androidToLwjglMap.put(KeyEvent.KEYCODE_7, Keyboard.KEY_7); androidToLwjglMap.put(KeyEvent.KEYCODE_8, Keyboard.KEY_8); androidToLwjglMap.put(KeyEvent.KEYCODE_9, Keyboard.KEY_9); + + // A-Z keys androidToLwjglMap.put(KeyEvent.KEYCODE_A, Keyboard.KEY_A); androidToLwjglMap.put(KeyEvent.KEYCODE_B, Keyboard.KEY_B); androidToLwjglMap.put(KeyEvent.KEYCODE_C, Keyboard.KEY_C); @@ -47,20 +53,36 @@ public class AndroidLWJGLKeycode { androidToLwjglMap.put(KeyEvent.KEYCODE_X, Keyboard.KEY_X); androidToLwjglMap.put(KeyEvent.KEYCODE_Y, Keyboard.KEY_Y); androidToLwjglMap.put(KeyEvent.KEYCODE_Z, Keyboard.KEY_Z); + + // Alt keys androidToLwjglMap.put(KeyEvent.KEYCODE_ALT_LEFT, Keyboard.KEY_LMENU); androidToLwjglMap.put(KeyEvent.KEYCODE_ALT_RIGHT, Keyboard.KEY_RMENU); - androidToLwjglMap.put(KeyEvent.KEYCODE_BACK, Keyboard.KEY_ESCAPE); // Might not be correctly! + + // Escape key + androidToLwjglMap.put(KeyEvent.KEYCODE_BACK, Keyboard.KEY_ESCAPE); + androidToLwjglMap.put(KeyEvent.KEYCODE_BACKSLASH, Keyboard.KEY_BACKSLASH); - // androidToLwjglMap.put(KeyEvent.keyCode_del, Keyboard.KEY_DELETE); androidToLwjglMap.put(KeyEvent.KEYCODE_BREAK, Keyboard.KEY_PAUSE); androidToLwjglMap.put(KeyEvent.KEYCODE_CAPS_LOCK, Keyboard.KEY_CAPITAL); androidToLwjglMap.put(KeyEvent.KEYCODE_COMMA, Keyboard.KEY_COMMA); + + // Control keys androidToLwjglMap.put(KeyEvent.KEYCODE_CTRL_LEFT, Keyboard.KEY_LCONTROL); androidToLwjglMap.put(KeyEvent.KEYCODE_CTRL_RIGHT, Keyboard.KEY_RCONTROL); + androidToLwjglMap.put(KeyEvent.KEYCODE_DEL, Keyboard.KEY_BACK); // Backspace + + // Arrow keys + androidToLwjglMap.put(KeyEvent.KEYCODE_DPAD_DOWN, Keyboard.KEY_DOWN); + androidToLwjglMap.put(KeyEvent.KEYCODE_DPAD_LEFT, Keyboard.KEY_LEFT); + androidToLwjglMap.put(KeyEvent.KEYCODE_DPAD_RIGHT, Keyboard.KEY_RIGHT); + androidToLwjglMap.put(KeyEvent.KEYCODE_DPAD_UP, Keyboard.KEY_UP); + androidToLwjglMap.put(KeyEvent.KEYCODE_ENTER, Keyboard.KEY_RETURN); androidToLwjglMap.put(KeyEvent.KEYCODE_EQUALS, Keyboard.KEY_EQUALS); androidToLwjglMap.put(KeyEvent.KEYCODE_ESCAPE, Keyboard.KEY_ESCAPE); + + // Fn keys androidToLwjglMap.put(KeyEvent.KEYCODE_F1, Keyboard.KEY_F1); androidToLwjglMap.put(KeyEvent.KEYCODE_F2, Keyboard.KEY_F2); androidToLwjglMap.put(KeyEvent.KEYCODE_F3, Keyboard.KEY_F3); @@ -74,13 +96,15 @@ public class AndroidLWJGLKeycode { androidToLwjglMap.put(KeyEvent.KEYCODE_F11, Keyboard.KEY_F11); androidToLwjglMap.put(KeyEvent.KEYCODE_F12, Keyboard.KEY_F12); androidToLwjglMap.put(KeyEvent.KEYCODE_FUNCTION, Keyboard.KEY_FUNCTION); - androidToLwjglMap.put(KeyEvent.KEYCODE_FORWARD, Keyboard.KEY_UP); // Might not be correctly; + androidToLwjglMap.put(KeyEvent.KEYCODE_GRAVE, Keyboard.KEY_GRAVE); androidToLwjglMap.put(KeyEvent.KEYCODE_HOME, Keyboard.KEY_HOME); androidToLwjglMap.put(KeyEvent.KEYCODE_INSERT, Keyboard.KEY_INSERT); androidToLwjglMap.put(KeyEvent.KEYCODE_KANA, Keyboard.KEY_KANA); androidToLwjglMap.put(KeyEvent.KEYCODE_LEFT_BRACKET, Keyboard.KEY_LBRACKET); androidToLwjglMap.put(KeyEvent.KEYCODE_MINUS, Keyboard.KEY_MINUS); + + // Num keys androidToLwjglMap.put(KeyEvent.KEYCODE_NUM_LOCK, Keyboard.KEY_NUMLOCK); androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_0, Keyboard.KEY_NUMPAD0); androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_1, Keyboard.KEY_NUMPAD1); @@ -92,23 +116,29 @@ public class AndroidLWJGLKeycode { androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_7, Keyboard.KEY_NUMPAD7); androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_8, Keyboard.KEY_NUMPAD8); androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_9, Keyboard.KEY_NUMPAD9); - androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_ENTER, Keyboard.KEY_NUMPADENTER); - androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_EQUALS, Keyboard.KEY_NUMPADEQUALS); - androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_COMMA, Keyboard.KEY_NUMPADCOMMA); androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_ADD, Keyboard.KEY_ADD); + androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_COMMA, Keyboard.KEY_NUMPADCOMMA); androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_DIVIDE, Keyboard.KEY_DIVIDE); androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_DOT, Keyboard.KEY_PERIOD); + androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_ENTER, Keyboard.KEY_NUMPADENTER); + androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_EQUALS, Keyboard.KEY_NUMPADEQUALS); androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_MULTIPLY, Keyboard.KEY_MULTIPLY); androidToLwjglMap.put(KeyEvent.KEYCODE_NUMPAD_SUBTRACT, Keyboard.KEY_SUBTRACT); + + // Page keys androidToLwjglMap.put(KeyEvent.KEYCODE_PAGE_DOWN, Keyboard.KEY_NEXT); androidToLwjglMap.put(KeyEvent.KEYCODE_PAGE_UP, Keyboard.KEY_PRIOR); + androidToLwjglMap.put(KeyEvent.KEYCODE_PERIOD, Keyboard.KEY_PERIOD); androidToLwjglMap.put(KeyEvent.KEYCODE_PLUS, Keyboard.KEY_ADD); androidToLwjglMap.put(KeyEvent.KEYCODE_POWER, Keyboard.KEY_POWER); androidToLwjglMap.put(KeyEvent.KEYCODE_RIGHT_BRACKET, Keyboard.KEY_RBRACKET); androidToLwjglMap.put(KeyEvent.KEYCODE_SEMICOLON, Keyboard.KEY_SEMICOLON); + + // Shift keys androidToLwjglMap.put(KeyEvent.KEYCODE_SHIFT_LEFT, Keyboard.KEY_LSHIFT); androidToLwjglMap.put(KeyEvent.KEYCODE_SHIFT_RIGHT, Keyboard.KEY_RSHIFT); + androidToLwjglMap.put(KeyEvent.KEYCODE_SLASH, Keyboard.KEY_SLASH); androidToLwjglMap.put(KeyEvent.KEYCODE_SLEEP, Keyboard.KEY_SLEEP); androidToLwjglMap.put(KeyEvent.KEYCODE_SPACE, Keyboard.KEY_SPACE); @@ -117,23 +147,53 @@ public class AndroidLWJGLKeycode { androidToLwjglMap.put(KeyEvent.KEYCODE_YEN, Keyboard.KEY_YEN); } - public static void execKey(MainActivity mainActivity, KeyEvent keyEvent, int i, boolean isDown) { - try { - System.out.println("Sending key as char: " + ((char) keyEvent.getUnicodeChar())); - mainActivity.sendKeyPress(0, (char) keyEvent.getUnicodeChar(), isDown); - } catch (Throwable th) { - th.printStackTrace(); + public static String[] generateKeyName() { + if (androidKeyNameArray == null) { + List keyName = new ArrayList(); + for (Integer perKey : androidToLwjglMap.keySet()) { + keyName.add(KeyEvent.keyCodeToString(perKey.intValue()).replace("KEYCODE_", "")); + } + androidKeyNameArray = keyName.toArray(new String[0]); } - + return androidKeyNameArray; + } + + public static void execKey(MainActivity mainActivity, KeyEvent keyEvent, int i, boolean isDown) { for (Map.Entry perKey : androidToLwjglMap.entrySet()) { if (perKey.getKey() == i) { - mainActivity.sendKeyPress(perKey.getValue(), isDown); + if (i == KeyEvent.KEYCODE_BACK && (keyEvent.getSource() == InputDevice.SOURCE_MOUSE)) { + // mainActivity.sendMo + } else { + mainActivity.sendKeyPress(perKey.getValue(), isDown); + } } } + if (keyEvent.isAltPressed()) { + mainActivity.sendKeyPress(Keyboard.KEY_LMENU, isDown); + } if (keyEvent.isCtrlPressed()) { + mainActivity.sendKeyPress(Keyboard.KEY_LCONTROL, isDown); + } if (keyEvent.isFunctionPressed()) { + mainActivity.sendKeyPress(Keyboard.KEY_FUNCTION, isDown); + } if (keyEvent.isShiftPressed()) { + mainActivity.sendKeyPress(Keyboard.KEY_LSHIFT, isDown); + } + + try { + if (/* (int) keyEvent.getDisplayLabel() != KeyEvent.KEYCODE_UNKNOWN && */ !AndroidDisplay.grab) { + mainActivity.sendKeyPress(0, (char) keyEvent.getUnicodeChar(), isDown); + } + } catch (Throwable th) { + th.printStackTrace(); + } + if (isBackspaceAfterChar && !AndroidDisplay.grab && i != KeyEvent.KEYCODE_DEL) { mainActivity.sendKeyPress(Keyboard.KEY_BACK, isDown); } } + + public static void execKeyIndex(MainActivity mainActivity, int index) { + mainActivity.sendKeyPress(androidToLwjglMap.valueAt(index)); + } } diff --git a/app/src/main/java/net/kdt/pojavlaunch/MCLauncherActivity.java b/app/src/main/java/net/kdt/pojavlaunch/MCLauncherActivity.java index 2a3c9b1cf..d6823475e 100644 --- a/app/src/main/java/net/kdt/pojavlaunch/MCLauncherActivity.java +++ b/app/src/main/java/net/kdt/pojavlaunch/MCLauncherActivity.java @@ -489,12 +489,14 @@ public class MCLauncherActivity extends AppCompatActivity String unpatchedPath = Tools.versnDir + downVName + "_unpatched.jar"; String patchedFile = Tools.versnDir + downVName + ".jar"; + JMinecraftVersionList.Version verInfo; + try { //com.pojavdx.dx.mod.Main.debug = true; String verJsonDir = Tools.versnDir + downVName + ".json"; - JMinecraftVersionList.Version verInfo = findVersion(p1[0]); + verInfo = findVersion(p1[0]); if (verInfo.url != null) { publishProgress("5", "Downloading " + p1[0] + " configuration..."); @@ -615,7 +617,7 @@ public class MCLauncherActivity extends AppCompatActivity convertStr = getStr(R.string.mcl_launch_convert_client, p1[0]); publishProgress("5", convertStr); addProgress = 0; - Tools.runDx(MCLauncherActivity.this, inputPath, outUnpatchedConvert.getAbsolutePath(), new PojavDXManager.Listen(){ + Tools.runDx(MCLauncherActivity.this, inputPath, outUnpatchedConvert.getAbsolutePath(), true, new PojavDXManager.Listen(){ @Override public void onReceived(String step, int maxProg, int currProg) @@ -665,7 +667,7 @@ public class MCLauncherActivity extends AppCompatActivity }); publishProgress("9", getStr(R.string.mcl_launch_download_assets)); try { - downloadAssets(p1[0], new File(Tools.ASSETS_PATH)); + downloadAssets(verInfo.assets, new File(Tools.ASSETS_PATH)); } catch (Exception e) { // Ignore it launchWithError = false; @@ -873,6 +875,7 @@ public class MCLauncherActivity extends AppCompatActivity public void modManager() { + /* File file1 = new File(Tools.mpModEnable); File file2 = new File(Tools.mpModDisable); File file3 = new File(Tools.mpModAddNewMo); @@ -911,6 +914,9 @@ public class MCLauncherActivity extends AppCompatActivity }); dialog.setView(flv); dialog.show(); + */ + + Tools.dialogOnUiThread(this, "Mods manager", "This feature is not yet supported!"); } public void openSelectMod() @@ -960,7 +966,8 @@ public class MCLauncherActivity extends AppCompatActivity dialog = new ProgressDialog(MCLauncherActivity.this); dialog.setTitle("Installing OptiFine"); dialog.setMessage("Prepaping"); - dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); + dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); + dialog.setMax(5); dialog.setCancelable(false); dialog.show(); } @@ -985,10 +992,12 @@ public class MCLauncherActivity extends AppCompatActivity Throwable throwable = null; File convertedFile = null; try { + publishProgress("Prepaping", "5"); + String origMd5 = OptiFinePatcher.calculateMD5(file[0]); convertedFile = new File(Tools.optifineDir, origMd5 + ".jar"); if (!convertedFile.exists()) { - publishProgress("(1/5) Patching OptiFine Installer"); + publishProgress("Patching OptiFine Installer", null, "1", "ADD"); Tools.extractAssetFolder(MCLauncherActivity.this, "optifine_patch", Tools.optifineDir, true); @@ -997,12 +1006,18 @@ public class MCLauncherActivity extends AppCompatActivity String[] output = Tools.patchOptifineInstaller(MCLauncherActivity.this, file[0]); File patchedFile = new File(output[1]); - publishProgress("(2/5) Converting OptiFine"); + publishProgress("Converting OptiFine", null, "1", "ADD"); System.setOut(new PrintStream(logOut)); System.setErr(new PrintStream(logErr)); - Tools.runDx(MCLauncherActivity.this, patchedFile.getAbsolutePath(), convertedFile.getAbsolutePath(), true, null); + Tools.runDx(MCLauncherActivity.this, patchedFile.getAbsolutePath(), convertedFile.getAbsolutePath(), true, new PojavDXManager.Listen(){ + @Override + public void onReceived(String msg, int max, int current) + { + publishProgress("Converting OptiFine: " + msg, Integer.toString(max), Integer.toString(current), "SET"); + } + }); if (!convertedFile.exists()) { RuntimeException dxError = new RuntimeException(getResources().getString(R.string.error_convert_lib, "OptiFine") + "\n" + currentLog.toString()); @@ -1013,23 +1028,23 @@ public class MCLauncherActivity extends AppCompatActivity patchedFile.delete(); } - publishProgress("(3/5) Launching OptiFine installer"); + publishProgress("Launching OptiFine installer", null, "1", "ADD"); File optDir = getDir("dalvik-cache", 0); optDir.mkdir(); DexClassLoader loader = new DexClassLoader(convertedFile.getAbsolutePath(), optDir.getAbsolutePath(), getApplicationInfo().nativeLibraryDir, getClass().getClassLoader()); - Tools.insertOptiFinePath(loader, convertedFile.getAbsolutePath()); + AndroidOptiFineUtilities.originalOptifineJar = convertedFile.getAbsolutePath(); Class installerClass = loader.loadClass("optifine.AndroidInstaller"); Method installerMethod = installerClass.getDeclaredMethod("doInstall", File.class); installerMethod.invoke(null, new File(Tools.MAIN_PATH)); - publishProgress("(4/5) Patching OptiFine Tweaker"); + publishProgress("(4/5) Patching OptiFine Tweaker", null, "1", "ADD"); File optifineLibFile = new File(AndroidOptiFineUtilities.optifineOutputJar); new OptiFinePatcher(optifineLibFile).saveTweaker(); - - publishProgress("(5/5) Done!"); + + publishProgress("(5/5) Done!", null, "1", "ADD"); Thread.sleep(500); } catch (Throwable th) { throwable = th; @@ -1044,17 +1059,26 @@ public class MCLauncherActivity extends AppCompatActivity return throwable; } } - +/* private Object fromConfig(DexClassLoader loader, String name) throws ReflectiveOperationException { Field f = loader.loadClass("Config").getDeclaredField(name); f.setAccessible(true); return f.get(null); } - +*/ @Override protected void onProgressUpdate(String[] text) { super.onProgressUpdate(text); dialog.setMessage(text[0]); + if (text.length >= 2 && text[1] != null) { + dialog.setMax(Integer.valueOf(text[1])); + } if (text.length >= 4) { + if (text[3].equals("ADD")) { + dialog.setProgress(dialog.getProgress() + Integer.valueOf(text[2])); + } else if (text[3].equals("SET")) { + dialog.setProgress(7 + Integer.valueOf(text[2])); + } + } } @Override diff --git a/app/src/main/java/net/kdt/pojavlaunch/MainActivity.java b/app/src/main/java/net/kdt/pojavlaunch/MainActivity.java index 8082aba9d..a43be2960 100644 --- a/app/src/main/java/net/kdt/pojavlaunch/MainActivity.java +++ b/app/src/main/java/net/kdt/pojavlaunch/MainActivity.java @@ -10,29 +10,31 @@ import android.support.v4.widget.*; import android.system.*; import android.util.*; import android.view.*; +import android.view.GestureDetector.*; import android.view.View.*; import android.view.inputmethod.*; import android.widget.*; +import com.android.internal.awt.*; import com.kdt.glsupport.*; +import com.kdt.pointer.*; import dalvik.system.*; import java.io.*; import java.lang.reflect.*; +import java.security.*; import java.util.*; +import javax.crypto.*; import javax.microedition.khronos.egl.*; import javax.microedition.khronos.opengles.*; import net.kdt.pojavlaunch.exit.*; -// import net.minecraft.launchwrapper.*; import org.lwjgl.input.*; import org.lwjgl.opengl.*; import org.lwjgl.util.applet.*; import org.lwjgl.util.glu.tessellation.*; import android.graphics.drawable.Drawable; -import android.view.GestureDetector.*; -import java.util.concurrent.locks.*; -import com.kdt.pointer.*; -import net.kdt.pojavlaunch.value.*; -import java.net.*; +import java.security.Provider.*; +import org.apache.harmony.security.fortress.*; +import optifine.*; public class MainActivity extends Activity implements OnTouchListener { @@ -49,6 +51,7 @@ public class MainActivity extends Activity implements OnTouchListener private int initialX; private int initialY; private static final int MSG_LEFT_MOUSE_BUTTON_CHECK = 1028; + private static final int MSG_DROP_ITEM_BUTTON_CHECK = 1029; private static boolean triggeredLeftMouseButton = false; private Handler theHandler = new Handler() { public void handleMessage(Message msg) { @@ -62,8 +65,10 @@ public class MainActivity extends Activity implements OnTouchListener triggeredLeftMouseButton = true; sendMouseButton(0, true); } - break; - } + } break; + case MSG_DROP_ITEM_BUTTON_CHECK: { + sendKeyPress(Keyboard.KEY_Q, true); + } break; } } }; @@ -96,13 +101,18 @@ public class MainActivity extends Activity implements OnTouchListener private ScrollView contentScroll; private ToggleButton toggleLog; private GestureDetector gestureDetector; + + private TextView debugText; private PointerOreoWrapper pointerSurface; + private View.OnTouchListener pointerCaptureListener; - private String mQueueText = new String(); + // private String mQueueText = new String(); private JMinecraftVersionList.Version mVersionInfo; + private View.OnTouchListener glTouchListener; + /* private LinearLayout contentCanvas; private AWTSurfaceView contentCanvasView; @@ -111,6 +121,8 @@ public class MainActivity extends Activity implements OnTouchListener private boolean lastGrab = false; private boolean isExited = false; private boolean isLogAllow = false; + + // private static Collection rsaPkcs1List; private String getStr(int id) { return getResources().getString(id); @@ -197,7 +209,9 @@ public class MainActivity extends Activity implements OnTouchListener break; case R.id.nav_viewlog: openLogOutput(); break; - case R.id.nav_fixdoubleletters: //openCanvasOutput(); + case R.id.nav_debug: toggleDebug(); + break; + case R.id.nav_customkey: dialogSendCustomKey(); } //Toast.makeText(MainActivity.this, menuItem.getTitle() + ":" + menuItem.getItemId(), Toast.LENGTH_SHORT).show(); @@ -239,11 +253,8 @@ public class MainActivity extends Activity implements OnTouchListener this.toggleLog.setChecked(false); this.textLogBehindGL = (TextView) findViewById(R.id.main_log_behind_GL); this.textLogBehindGL.setTypeface(Typeface.MONOSPACE); - + this.textLog.setTypeface(Typeface.MONOSPACE); - - this.glSurfaceView = (MinecraftGLView) findViewById(R.id.main_game_render_view); - this.toggleLog.setOnCheckedChangeListener(new ToggleButton.OnCheckedChangeListener(){ @Override @@ -254,6 +265,11 @@ public class MainActivity extends Activity implements OnTouchListener } }); + this.debugText = (TextView) findViewById(R.id.content_text_debug); + + this.glSurfaceView = (MinecraftGLView) findViewById(R.id.main_game_render_view); + + toggleGui(null); this.drawerLayout.closeDrawers(); @@ -305,7 +321,7 @@ public class MainActivity extends Activity implements OnTouchListener } }).start(); - // Touch pad + // ORIGINAL Touch pad touchPad.setOnTouchListener(new OnTouchListener(){ private float prevX, prevY; @Override @@ -331,18 +347,6 @@ public class MainActivity extends Activity implements OnTouchListener } else { switch (action) { - /* - case MotionEvent.ACTION_DOWN: // 0 - case MotionEvent.ACTION_POINTER_DOWN: // 5 - if (mVelocityTracker == null) { - mVelocityTracker = VelocityTracker.obtain(); - } - else { - mVelocityTracker.clear(); - } - mVelocityTracker.addMovement(event); - break; - */ case MotionEvent.ACTION_UP: // 1 case MotionEvent.ACTION_CANCEL: // 3 case MotionEvent.ACTION_POINTER_UP: // 6 @@ -377,79 +381,189 @@ public class MainActivity extends Activity implements OnTouchListener return true; } }); - + System.loadLibrary("gl04es"); + Bitmap awtGraphics = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888); + AndroidGraphics2D.getInstance(this, new Canvas(awtGraphics), null); + glSurfaceView.setFocusable(true); glSurfaceView.setFocusableInTouchMode(true); glSurfaceView.setEGLContextClientVersion(2); - final View.OnTouchListener glTouchListener = new OnTouchListener(){ - + glTouchListener = new OnTouchListener(){ + private boolean isTouchInHotbar = false; + private int hotbarX, hotbarY; @Override public boolean onTouch(View p1, MotionEvent e) { + // System.out.println("Pre touch, isTouchInHotbar=" + Boolean.toString(isTouchInHotbar) + ", action=" + MotionEvent.actionToString(e.getActionMasked())); + int x = ((int) e.getX()) / scaleFactor; int y = (glSurfaceView.getHeight() - ((int) e.getY())) / scaleFactor; - if (handleGuiBar(x, y, e)) { - return true; - } else if (!AndroidDisplay.grab && gestureDetector.onTouchEvent(e)) { - AndroidDisplay.putMouseEventWithCoords(rightOverride ? (byte) 1 : (byte) 0, (byte) 1, x, y, 0, System.nanoTime()); - AndroidDisplay.putMouseEventWithCoords(rightOverride ? (byte) 1 : (byte) 0, (byte) 0, x, y, 0, System.nanoTime()); - if (!rightOverride) { - AndroidDisplay.mouseLeft = true; + int hudKeyHandled = handleGuiBar(x, y, e); + if (!AndroidDisplay.grab && gestureDetector.onTouchEvent(e)) { + if (hudKeyHandled != -1) { + sendKeyPress(hudKeyHandled); + } else { + AndroidDisplay.putMouseEventWithCoords(rightOverride ? (byte) 1 : (byte) 0, (byte) 1, x, y, 0, System.nanoTime()); + AndroidDisplay.putMouseEventWithCoords(rightOverride ? (byte) 1 : (byte) 0, (byte) 0, x, y, 0, System.nanoTime()); + if (!rightOverride) { + AndroidDisplay.mouseLeft = true; + } } - return true; } else { - AndroidDisplay.mouseX = x; - AndroidDisplay.mouseY = y; switch (e.getActionMasked()) { case e.ACTION_DOWN: // 0 case e.ACTION_POINTER_DOWN: // 5 - if (!rightOverride) { - AndroidDisplay.mouseLeft = true; - } - - if (AndroidDisplay.grab) { - AndroidDisplay.putMouseEventWithCoords(rightOverride ? (byte) 1 : (byte) 0, (byte) 1, x, y, 0, System.nanoTime()); - initialX = x; - initialY = y; - theHandler.sendEmptyMessageDelayed(MainActivity.MSG_LEFT_MOUSE_BUTTON_CHECK, 500); - break; + isTouchInHotbar = hudKeyHandled != -1; + if (isTouchInHotbar) { + sendKeyPress(hudKeyHandled, true); + hotbarX = x; + hotbarY = y; + + theHandler.sendEmptyMessageDelayed(MainActivity.MSG_DROP_ITEM_BUTTON_CHECK, 500); + } else { + AndroidDisplay.mouseX = x; + AndroidDisplay.mouseY = y; + if (!rightOverride) { + AndroidDisplay.mouseLeft = true; + } + if (AndroidDisplay.grab) { + AndroidDisplay.putMouseEventWithCoords(rightOverride ? (byte) 1 : (byte) 0, (byte) 1, x, y, 0, System.nanoTime()); + initialX = x; + initialY = y; + theHandler.sendEmptyMessageDelayed(MainActivity.MSG_LEFT_MOUSE_BUTTON_CHECK, 500); + } } break; - case e.ACTION_UP: // 1 case e.ACTION_CANCEL: // 3 case e.ACTION_POINTER_UP: // 6 - AndroidDisplay.putMouseEventWithCoords(rightOverride ? (byte) 1 : (byte) 0, (byte) 0, x, y, 0, System.nanoTime()); - if (!rightOverride) { - AndroidDisplay.mouseLeft = false; - } - + if (!isTouchInHotbar) { + AndroidDisplay.mouseX = x; + AndroidDisplay.mouseY = y; + + AndroidDisplay.putMouseEventWithCoords(rightOverride ? (byte) 1 : (byte) 0, (byte) 0, x, y, 0, System.nanoTime()); + if (!rightOverride) { + AndroidDisplay.mouseLeft = false; + } + } + if (AndroidDisplay.grab) { - /* - initialX = x; - initialY = y; - - theHandler.sendEmptyMessageDelayed(MainActivity.MSG_LEFT_MOUSE_BUTTON_CHECK, 500); - */ - - if (!triggeredLeftMouseButton && Math.abs(initialX - x) < fingerStillThreshold && Math.abs(initialY - y) < fingerStillThreshold) { + // System.out.println((String) ("[Math.abs(" + initialX + " - " + x + ") = " + Math.abs(initialX - x) + "] < " + fingerStillThreshold)); + // System.out.println((String) ("[Math.abs(" + initialY + " - " + y + ") = " + Math.abs(initialY - y) + "] < " + fingerStillThreshold)); + if (isTouchInHotbar && Math.abs(hotbarX - x) < fingerStillThreshold && Math.abs(hotbarY - y) < fingerStillThreshold) { + sendKeyPress(hudKeyHandled, false); + } else if (!triggeredLeftMouseButton && Math.abs(initialX - x) < fingerStillThreshold && Math.abs(initialY - y) < fingerStillThreshold) { sendMouseButton(1, true); sendMouseButton(1, false); } - if (triggeredLeftMouseButton) { - sendMouseButton(0, false); + if (!isTouchInHotbar) { + if (triggeredLeftMouseButton) { + sendMouseButton(0, false); + } + triggeredLeftMouseButton = false; + theHandler.removeMessages(MainActivity.MSG_LEFT_MOUSE_BUTTON_CHECK); + } else { + sendKeyPress(Keyboard.KEY_Q, false); + theHandler.removeMessages(MSG_DROP_ITEM_BUTTON_CHECK); } - triggeredLeftMouseButton = false; - theHandler.removeMessages(MainActivity.MSG_LEFT_MOUSE_BUTTON_CHECK); - break; + } + break; + + default: + if (!isTouchInHotbar) { + AndroidDisplay.mouseX = x; + AndroidDisplay.mouseY = y; } break; } } + // System.out.println("Post touch, isTouchInHotbar=" + Boolean.toString(isTouchInHotbar) + ", action=" + MotionEvent.actionToString(e.getActionMasked())); + + return true; + // If onClick fail with false, change back to true + } + }; + + pointerCaptureListener = new OnTouchListener(){ + private int x, y; + + private String getMoving(int pos, boolean xOrY) { + if (pos == 0) { + return "STOPPED"; + } else if (pos > 0) { + return xOrY ? "RIGHT" : "DOWN"; + } else { // if (pos3 < 0) { + return xOrY ? "LEFT" : "UP"; + } + } + + @Override + public boolean onTouch(View p1, MotionEvent e) + { + StringBuilder builder = new StringBuilder(); + builder.append("PointerCapture debug\n"); + builder.append("MotionEvent=" + e.getActionMasked() + "\n\n"); + + builder.append("PointerX=" + e.getX() + "\n"); + builder.append("PointerY=" + e.getY() + "\n"); + builder.append("RawX=" + e.getRawX() + "\n"); + builder.append("RawY=" + e.getRawY() + "\n\n"); + + x += ((int) e.getX()) / scaleFactor; + y -= ((int) e.getY()) / scaleFactor; + + builder.append("XPos=" + x + "\n"); + builder.append("YPos=" + y + "\n\n"); + builder.append("MovingX=" + getMoving(x, true) + "\n"); + builder.append("MovingY=" + getMoving(y, false) + "\n"); + + debugText.setText(builder.toString()); + + AndroidDisplay.mouseX = x; + AndroidDisplay.mouseY = y; + + switch (e.getButtonState()) { + case MotionEvent.BUTTON_PRIMARY: AndroidDisplay.mouseLeft = true; + break; + case MotionEvent.BUTTON_SECONDARY: AndroidDisplay.mouseLeft = false; + break; + } + + switch (e.getActionMasked()) { + case e.ACTION_DOWN: // 0 + case e.ACTION_POINTER_DOWN: // 5 + AndroidDisplay.putMouseEventWithCoords(rightOverride ? (byte) 1 : (byte) 0, (byte) 1, x, y, 0, System.nanoTime()); + initialX = x; + initialY = y; + theHandler.sendEmptyMessageDelayed(MainActivity.MSG_LEFT_MOUSE_BUTTON_CHECK, 500); + break; + + case e.ACTION_UP: // 1 + case e.ACTION_CANCEL: // 3 + case e.ACTION_POINTER_UP: // 6 + AndroidDisplay.putMouseEventWithCoords(rightOverride ? (byte) 1 : (byte) 0, (byte) 0, x, y, 0, System.nanoTime()); + /* + if (!triggeredLeftMouseButton && Math.abs(initialX - x) < fingerStillThreshold && Math.abs(initialY - y) < fingerStillThreshold) { + sendMouseButton(1, true); + sendMouseButton(1, false); + } + if (triggeredLeftMouseButton) { + sendMouseButton(0, false); + } + */ + + sendMouseButton(AndroidDisplay.mouseLeft ? 0 : 1, true); + sendMouseButton(AndroidDisplay.mouseLeft ? 0 : 1, false); + + // triggeredLeftMouseButton = false; + theHandler.removeMessages(MainActivity.MSG_LEFT_MOUSE_BUTTON_CHECK); + break; + } + return true; // If onClick fail with false, change back to true } @@ -458,20 +572,16 @@ public class MainActivity extends Activity implements OnTouchListener if (isPointerCaptureSupported()) { this.pointerSurface = new PointerOreoWrapper(glSurfaceView); this.pointerSurface.setOnCapturedPointerListener(new PointerOreoWrapper.OnCapturedPointerListener(){ - - @Override - public boolean onCapturedPointer(View view, MotionEvent event) - { - return glTouchListener.onTouch(view, event); - } - }); + @Override + public boolean onCapturedPointer(View view, MotionEvent event) { + return pointerCaptureListener.onTouch(view, event); + } + }); } glSurfaceView.setOnHoverListener(new View.OnHoverListener(){ - @Override - public boolean onHover(View p1, MotionEvent p2) - { + public boolean onHover(View p1, MotionEvent p2) { if (!AndroidDisplay.grab) { return glTouchListener.onTouch(p1, p2); } @@ -605,7 +715,7 @@ public class MainActivity extends Activity implements OnTouchListener super.onPause(); } - public void fullyExit() { + public static void fullyExit() { ExitManager.stopExitLoop(); } @@ -639,9 +749,12 @@ public class MainActivity extends Activity implements OnTouchListener // Disable javax management for smaller launcher. System.setProperty("log4j2.disable.jmx", "true"); - + //System.setProperty("net.zhuoweizhang.boardwalk.org.apache.logging.log4j.level", "INFO"); //System.setProperty("net.zhuoweizhang.boardwalk.org.apache.logging.log4j.simplelog.level", "INFO"); + + // Change info for useful dump + System.setProperty("java.vm.info", Build.MANUFACTURER + " " + Build.MODEL + " [Android " + Build.VERSION.SDK_INT + "]"); } catch (Exception e) { Tools.showError(MainActivity.this, e, true); } @@ -666,7 +779,7 @@ public class MainActivity extends Activity implements OnTouchListener varArgMap.put("version_name", versionName); varArgMap.put("game_directory", gameDir.getAbsolutePath()); varArgMap.put("assets_root", mcAssetsDir); - varArgMap.put("assets_index_name", versionName); + varArgMap.put("assets_index_name", mVersionInfo.assets); varArgMap.put("auth_uuid", mProfile.getProfileID()); varArgMap.put("auth_access_token", mProfile.getAccessToken()); varArgMap.put("user_properties", "{}"); @@ -674,10 +787,22 @@ public class MainActivity extends Activity implements OnTouchListener varArgMap.put("version_type", mVersionInfo.type); varArgMap.put("game_assets", Tools.ASSETS_PATH); - String[] argsFromJson = insertVariableArgument(mVersionInfo.minecraftArguments.split(" "), varArgMap); + String[] argsFromJson = insertVariableArgument(splitAndFilterEmpty(mVersionInfo.minecraftArguments), varArgMap); + // Tools.dialogOnUiThread(this, "Result args", Arrays.asList(argsFromJson).toString()); return argsFromJson; } + private String[] splitAndFilterEmpty(String argStr) { + List strList = new ArrayList(); + strList.add("--fullscreen"); + for (String arg : argStr.split(" ")) { + if (!arg.isEmpty()) { + strList.add(arg); + } + } + return strList.toArray(new String[0]); + } + private String[] insertVariableArgument(String[] args, Map keyValueMap) { for (int i = 0; i < args.length; i++) { String arg = args[i]; @@ -701,6 +826,14 @@ public class MainActivity extends Activity implements OnTouchListener { String[] launchArgs = getMCArgs(); + // Setup OptiFine + if (mVersionInfo.optifineLib != null) { + String[] optifineInfo = mVersionInfo.optifineLib.name.split(":"); + String optifineJar = Tools.libraries + "/" + Tools.artifactToPath(optifineInfo[0], optifineInfo[1], optifineInfo[2]); + + AndroidOptiFineUtilities.originalOptifineJar = optifineJar; + } + File optDir = getDir("dalvik-cache", 0); optDir.mkdirs(); @@ -725,6 +858,8 @@ public class MainActivity extends Activity implements OnTouchListener PrintStream theStreamErr = new PrintStream(new LoggerJava.LoggerOutputStream(System.err, printLog)); System.setErr(theStreamErr); + + fixRSAPadding(); System.out.println("> Running Minecraft with classpath:"); System.out.println(launchClassPath); @@ -733,14 +868,6 @@ public class MainActivity extends Activity implements OnTouchListener // Load classpath DexClassLoader launchBaseLoader = new DexClassLoader(launchClassPath, launchOptimizedDirectory, launchLibrarySearchPath, getClassLoader()); - // Setup OptiFine - if (mVersionInfo.optifineLib != null) { - String[] optifineInfo = mVersionInfo.optifineLib.name.split(":"); - String optifineJar = Tools.artifactToPath(optifineInfo[0], optifineInfo[1], optifineInfo[2]); - - Tools.insertOptiFinePath(launchBaseLoader, optifineJar); - } - // Launch Minecraft Class mainClass = launchBaseLoader.loadClass(mVersionInfo.mainClass); Method mainMethod = mainClass.getMethod("main", String[].class); @@ -759,6 +886,46 @@ public class MainActivity extends Activity implements OnTouchListener * [3] = mainclass (eg. "net.minecraft.client.Minecraft") */ } + + public void fixRSAPadding() throws Exception { + // welcome to the territory of YOLO; I'll be your tour guide for today. + + try { + System.out.println(Cipher.getInstance("RSA")); + System.out.println(Cipher.getInstance("RSA/ECB/PKCS1Padding")); + if (android.os.Build.VERSION.SDK_INT >= 23) { // Marshmallow + // return; // FUUUUU I DON'T KNOW FIXME + } + + ArrayList rsaList = Services.getServices("Cipher.RSA"); + ArrayList rsaPkcs1List = Services.getServices("Cipher.RSA/ECB/PKCS1PADDING"); + + rsaList.clear(); + rsaList.addAll(rsaPkcs1List); + } catch (Throwable th) { + // Tools.dialogOnUiThread(MainActivity.this, "Warning: can't fix RSA Padding", Log.getStackTraceString(th)); + th.printStackTrace(); + + runOnUiThread(new Runnable(){ + + @Override + public void run() + { + Toast.makeText(MainActivity.this, "Unable to fix RSAPadding. You can't play premium servers", Toast.LENGTH_LONG).show(); + } + }); + } + + + //System.out.println("After: " + KeyFactory.getInstance("RSA") + ":" + KeyFactory.getInstance("RSA").getProvider()); + + /* Provider provider = KeyFactory.getInstance("RSA").getProvider(); + System.out.println("Before: " + provider.getService("KeyService", "RSA")); + Provider.Service service = provider.getService("KeyService", "RSA/ECB/PKCS5Padding"); + System.out.println(service); + provider.putService(service); + System.out.println("After: " + provider.getService("KeyService", "RSA"));*/ + } public void printStream(InputStream stream) { try { @@ -780,6 +947,23 @@ public class MainActivity extends Activity implements OnTouchListener return s; } + private void toggleDebug() { + debugText.setVisibility(debugText.getVisibility() == View.GONE ? View.VISIBLE : View.GONE); + } + + private void dialogSendCustomKey() { + AlertDialog.Builder dialog = new AlertDialog.Builder(this); + dialog.setTitle(R.string.control_customkey); + dialog.setItems(AndroidLWJGLKeycode.generateKeyName(), new DialogInterface.OnClickListener(){ + + @Override + public void onClick(DialogInterface dInterface, int position) { + AndroidLWJGLKeycode.execKeyIndex(MainActivity.this, position); + } + }); + dialog.show(); + } + private void openLogOutput() { WindowAnimation.fadeIn(contentLog, 500); } @@ -829,6 +1013,22 @@ public class MainActivity extends Activity implements OnTouchListener return; } } + + public String getMinecraftOption(String key) { + try { + String[] options = Tools.read(Tools.MAIN_PATH + "/options.txt").split("\n"); + for (String option : options) { + String[] optionKeyValue = option.split(":"); + if (optionKeyValue[0].equals(key)) { + return optionKeyValue[1]; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return ""; + } + public int mcscale(int input) { return this.guiScale * input; } @@ -915,7 +1115,8 @@ public class MainActivity extends Activity implements OnTouchListener default: return false; } - if (v == this.upButton) { + + if (v == this.upButton) { sendKeyPress(Keyboard.KEY_W, isDown); } else if (v == this.downButton) { sendKeyPress(Keyboard.KEY_S, isDown); @@ -1011,34 +1212,20 @@ public class MainActivity extends Activity implements OnTouchListener this.guiScale = scale; } - public boolean handleGuiBar(int x, int y, MotionEvent e) { + public int handleGuiBar(int x, int y, MotionEvent e) { if (!AndroidDisplay.grab) { - return false; - } - boolean isDown; - switch (e.getActionMasked()) { - case 0: - case 5: - isDown = true; - break; - case 1: - case 3: - case 6: - isDown = false; - break; - default: - return false; + return -1; } + int screenWidth = AndroidDisplay.windowWidth; int screenHeight = AndroidDisplay.windowHeight; int barheight = mcscale(20); int barwidth = mcscale(180); int barx = (screenWidth / 2) - (barwidth / 2); if (x < barx || x >= barx + barwidth || y < 0 || y >= 0 + barheight) { - return false; + return -1; } - sendKeyPress(hotbarKeys[((x - barx) / mcscale(20)) % 9], isDown); - return true; + return hotbarKeys[((x - barx) / mcscale(20)) % 9]; } private class SingleTapConfirm extends SimpleOnGestureListener diff --git a/app/src/main/java/net/kdt/pojavlaunch/PojavLoginActivity.java b/app/src/main/java/net/kdt/pojavlaunch/PojavLoginActivity.java index ad2a8477c..f7588eff0 100644 --- a/app/src/main/java/net/kdt/pojavlaunch/PojavLoginActivity.java +++ b/app/src/main/java/net/kdt/pojavlaunch/PojavLoginActivity.java @@ -302,8 +302,8 @@ public class PojavLoginActivity extends MineActivity mkdirs(Tools.MAIN_PATH); Tools.copyAssetFile(this, "options.txt", Tools.MAIN_PATH, false); - //Tools.copyAssetToFolderIfNonExist(this, "dx-f" + (isAndroid7() ? "7" : "4") + ".0.jar", Tools.worksDir, "dx.jar"); - Tools.copyAssetFile(this, "pojavdx.dex", Tools.worksDir, true); + // Tools.copyAssetToFolderIfNonExist(this, "dx-f" + (isAndroid7() ? "7" : "4") + ".0.jar", Tools.worksDir, "dx.jar"); + // Tools.copyAssetFile(this, "pojavdx.dex", Tools.worksDir, true); // Copy ZIP!!! diff --git a/app/src/main/java/net/kdt/pojavlaunch/Tools.java b/app/src/main/java/net/kdt/pojavlaunch/Tools.java index 509a917c9..ffacee48a 100644 --- a/app/src/main/java/net/kdt/pojavlaunch/Tools.java +++ b/app/src/main/java/net/kdt/pojavlaunch/Tools.java @@ -20,6 +20,10 @@ import net.kdt.pojavlaunch.patcher.*; import java.lang.reflect.*; import dalvik.system.*; import optifine.*; +import android.text.*; +import java.awt.*; +import javax.xml.transform.*; +import java.awt.datatransfer.*; public final class Tools { @@ -30,7 +34,7 @@ public final class Tools public static String ASSETS_PATH = MAIN_PATH + "/assets"; public static int usingVerCode = 1; - public static String usingVerName = "2.0"; + public static String usingVerName = "2.4.2"; public static String mhomeUrl = "http://mineup.eu5.net"; // "http://kdtjavacraft.eu5.net"; public static String datapath = "/data/data/net.kdt.pojavlaunch"; public static String worksDir = datapath + "/app_working_dir"; @@ -143,10 +147,6 @@ public final class Tools showError(ctx, e); } } - - public static void insertOptiFinePath(BaseDexClassLoader loader, String optifineJar) throws NoSuchFieldException, IllegalAccessException, IllegalArgumentException, ClassNotFoundException { - AndroidOptiFineUtilities.originalOptifineJar = optifineJar; - } /* public static void extractLibraries(Activity ctx) throws Exception @@ -181,8 +181,13 @@ public final class Tools @Override public void onClick(DialogInterface p1, int p2) { - if(exitIfOk) // MainActivity.fullyExit(); - ctx.finish(); + if(exitIfOk) { + if (ctx instanceof MainActivity) { + MainActivity.fullyExit(); + } else { + ctx.finish(); + } + } } }) .setNegativeButton(showMore ? R.string.error_show_less : R.string.error_show_more, new DialogInterface.OnClickListener(){ @@ -198,14 +203,16 @@ public final class Tools @Override public void onClick(DialogInterface p1, int p2) { - ClipboardManager clipboard = (ClipboardManager) ctx.getSystemService(Context.CLIPBOARD_SERVICE); - ClipData clip = ClipData.newPlainText("Error", errMsg); - clipboard.setPrimaryClip(clip); + StringSelection errData = new StringSelection(errMsg); + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(errData, null); - Toast.makeText(ctx, "Copied to clipboard", Toast.LENGTH_SHORT).show(); - - if(exitIfOk) // MainActivity.fullyExit(); - ctx.finish(); + if(exitIfOk) { + if (ctx instanceof MainActivity) { + MainActivity.fullyExit(); + } else { + ctx.finish(); + } + } } }) //.setNegativeButton("Report (not available)", null) @@ -456,21 +463,20 @@ public final class Tools } public static byte[] loadFromAssetToByte(Context ctx, String inFile) { - byte[] tContents = {}; + byte[] buffer = null; try { InputStream stream = ctx.getAssets().open(inFile); int size = stream.available(); - byte[] buffer = new byte[size]; + buffer = new byte[size]; stream.read(buffer); stream.close(); - tContents = buffer; } catch (IOException e) { // Handle exceptions here e.printStackTrace(); } - return tContents; + return buffer; } public static void downloadFile(String urlInput, String nameOutput, boolean requireNonExist) throws Throwable diff --git a/app/src/main/java/net/minecraft/launchwrapper/Launch.java b/app/src/main/java/net/minecraft/launchwrapper/Launch.java index 529fb6dd1..3f0c5d08f 100644 --- a/app/src/main/java/net/minecraft/launchwrapper/Launch.java +++ b/app/src/main/java/net/minecraft/launchwrapper/Launch.java @@ -7,14 +7,13 @@ import java.util.logging.*; import joptsimple.*; import net.kdt.pojavlaunch.*; import net.kdt.pojavlaunch.value.*; +import optifine.*; public class Launch { private static final String DEFAULT_TWEAK = "net.minecraft.launchwrapper.VanillaTweaker"; public static File minecraftHome; public static File assetsDir; public static Map blackboard; - - public static DependentLibrary optifineLib; public static void main(String[] args) { new Launch().launch(args); @@ -26,17 +25,6 @@ public class Launch { // final URLClassLoader ucl = (URLClassLoader) getClass().getClassLoader(); classLoader = new LaunchClassLoader(); // (getClass().getClassLoader()); - if (optifineLib != null) { - String[] optifineInfo = optifineLib.name.split(":"); - String optifineJar = Tools.artifactToPath(optifineInfo[0], optifineInfo[1], optifineInfo[2]); - - try { - Tools.insertOptiFinePath(classLoader, optifineJar); - } catch (Throwable th) { - throw new RuntimeException(th); - } - } - blackboard = new HashMap(); Thread.currentThread().setContextClassLoader(classLoader); } diff --git a/app/src/main/java/net/minecraft/launchwrapper/LaunchClassLoader.java b/app/src/main/java/net/minecraft/launchwrapper/LaunchClassLoader.java index 751756a03..ddf0de3d2 100644 --- a/app/src/main/java/net/minecraft/launchwrapper/LaunchClassLoader.java +++ b/app/src/main/java/net/minecraft/launchwrapper/LaunchClassLoader.java @@ -418,12 +418,12 @@ public class LaunchClassLoader extends BaseDexClassLoader { totalLength += read; if (totalLength >= buffer.length - 1) { byte[] newBuffer = new byte[(buffer.length + BUFFER_SIZE)]; - System.arraycopy(buffer, 0, newBuffer, 0, buffer.length); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(buffer, 0, newBuffer, 0, buffer.length); buffer = newBuffer; } } else { byte[] result = new byte[totalLength]; - System.arraycopy(buffer, 0, result, 0, totalLength); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(buffer, 0, result, 0, totalLength); return result; } } diff --git a/app/src/main/java/optifine/AndroidOptiFineUtilities.java b/app/src/main/java/optifine/AndroidOptiFineUtilities.java index d0fe2cbe1..f40725085 100644 --- a/app/src/main/java/optifine/AndroidOptiFineUtilities.java +++ b/app/src/main/java/optifine/AndroidOptiFineUtilities.java @@ -2,5 +2,8 @@ package optifine; public class AndroidOptiFineUtilities { - public static String originalOptifineJar, optifineOutputJar; + public static volatile String originalOptifineJar; + public static volatile String optifineOutputJar; + + // public sta } diff --git a/app/src/main/java/org/apache/harmony/awt/ChoiceStyle.java b/app/src/main/java/org/apache/harmony/awt/ChoiceStyle.java new file mode 100644 index 000000000..93b7aada2 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/ChoiceStyle.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Dmitry A. Durnev + * @version $Revision$ + */ +package org.apache.harmony.awt; + +/** + * ChoiceStyle. + * Is used to define custom choice properties: + * width and x screen coordinate of the list popup window. + */ +public interface ChoiceStyle { + + int getPopupX(int x, int width, int choiceWidth, int screenWidth); + int getPopupWidth(int choiceWidth); + +} diff --git a/app/src/main/java/org/apache/harmony/awt/ClipRegion.java b/app/src/main/java/org/apache/harmony/awt/ClipRegion.java new file mode 100644 index 000000000..c89a81dd1 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/ClipRegion.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov, Anton Avtamonov + * @version $Revision$ + */ +package org.apache.harmony.awt; + +import java.awt.Component; +import java.awt.Rectangle; + +import org.apache.harmony.awt.gl.MultiRectArea; +import org.apache.harmony.awt.internal.nls.Messages; + +public class ClipRegion extends Rectangle { + private final MultiRectArea clip; + + public ClipRegion(final MultiRectArea clip) { + this.clip = new MultiRectArea(clip); + setBounds(clip.getBounds()); + } + + public MultiRectArea getClip() { + return clip; + } + + @Override + public String toString() { + String str = clip.toString(); + int i = str.indexOf('['); + str = str.substring(i); + if (clip.getRectCount() == 1) { + str = str.substring(1, str.length() - 1); + } + return getClass().getName() + str; + } + + + public void convertRegion(final Component child, final Component parent) { + convertRegion(child, clip, parent); + } + + public void intersect(final Rectangle rect) { + clip.intersect(rect); + } + + @Override + public boolean isEmpty() { + return clip.isEmpty(); + } + + public static void convertRegion(final Component child, + final MultiRectArea region, + final Component parent) { + int x = 0, y = 0; + Component c = child; + //???AWT + /* + for (; c != null && c != parent; c = c.getParent()) { + x += c.getX(); + y += c.getY(); + } + */ + if (c == null) { + // awt.51=Component expected to be a parent + throw new IllegalArgumentException(Messages.getString("awt.51")); //$NON-NLS-1$ + } + region.translate(x, y); + } +} diff --git a/app/src/main/java/org/apache/harmony/awt/ComponentInternals.java b/app/src/main/java/org/apache/harmony/awt/ComponentInternals.java new file mode 100644 index 000000000..c3597846e --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/ComponentInternals.java @@ -0,0 +1,212 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package org.apache.harmony.awt; + +//???AWT +//import java.awt.Component; +//import java.awt.Container; +//import java.awt.Dialog; +import java.awt.Dimension; +//import java.awt.Image; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +//import java.awt.Window; +//import java.awt.Choice; +import java.lang.reflect.InvocationTargetException; + +import org.apache.harmony.awt.gl.MultiRectArea; +//import org.apache.harmony.awt.text.TextFieldKit; +//import org.apache.harmony.awt.text.TextKit; +//import org.apache.harmony.awt.wtk.NativeWindow; + +import org.apache.harmony.luni.util.NotImplementedException; + +/** + * The accessor to AWT private API + */ +public abstract class ComponentInternals { + + /** + * @return the ComponentInternals instance to serve the requests + */ + public static ComponentInternals getComponentInternals() { + return ContextStorage.getComponentInternals(); + } + + /** + * This method must be called by AWT to establish the connection + * @param internals - implementation of ComponentInternals created by AWT + */ + public static void setComponentInternals(ComponentInternals internals) { + ContextStorage.setComponentInternals(internals); + } + + /** + * The accessor to native resource connected to a component. + * It returns non-null value only if component + * already has the native resource + */ + //public abstract NativeWindow getNativeWindow(Component component); + + /** + * Connect Window object to existing native resource + * @param nativeWindowId - id of native window to attach + * @return Window object with special behaviour that + * restricts manupulation with that window + */ + //public abstract Window attachNativeWindow(long nativeWindowId); + + /** + * Start mouse grab in "client" mode. + * All mouse events in AWT components will be reported as usual, + * mouse events that occured outside of AWT components will be sent to + * the window passed as grabWindow parameter. When mouse grab is canceled + * (because of click in non-AWT window or by task switching) + * the whenCanceled callback is called + * + * @param grabWindow - window that will own the grab + * @param whenCanceled - callback called when grab is canceled by user's action + */ + //public abstract void startMouseGrab(Window grabWindow, Runnable whenCanceled); + + /** + * End mouse grab and resume normal processing of mouse events + */ + //public abstract void endMouseGrab(); + + /** + * Set the popup flag of the window to true. + * This window won't be controlled by window manager on Linux. + * Call this method before the window is shown first time + * @param window - the window that should become popup one + */ + //public abstract void makePopup(Window window); + + /** + * This method must be called by Graphics at the beginning of drawImage() + * to store image drawing parameters (defined by application developer) in component + * + * @param comp - component that draws the image + * @param image - image to be drawn + * @param destLocation - location of the image upon the component's surface. Never null. + * @param destSize - size of the component's area to be filled with the image. + * Equals to null if size parameters omitted in drawImage. + * @param source - area of the image to be drawn on the component. + * Equals to null if src parameters omitted in drawImage. + */ + /* + public abstract void onDrawImage(Component comp, Image image, Point destLocation, + Dimension destSize, Rectangle source); +*/ + /** + * Sets system's caret position. + * This method should be called by text component to synchronize our caret position + * with system's caret position. + * @param x + * @param y + */ + //public abstract void setCaretPos(Component c, int x, int y); + + /** + * NEVER USE IT. FORGET IT. IT DOES NOT EXIST. + * See Toolkit.unsafeInvokeAndWait(Runnable). + * + * Accessor for Toolkit.unsafeInvokeAndWait(Runnable) method. + * For use in exceptional cases only. + * Read comments for Toolkit.unsafeInvokeAndWait(Runnable) before use. + */ + /* + public abstract void unsafeInvokeAndWait(Runnable runnable) + throws InterruptedException, InvocationTargetException; + + public abstract TextKit getTextKit(Component comp); + + public abstract void setTextKit(Component comp, TextKit kit); + + public abstract TextFieldKit getTextFieldKit(Component comp); + + public abstract void setTextFieldKit(Component comp, TextFieldKit kit); +*/ + /** + * Terminate event dispatch thread, completely destroy AWT context.
    + * Intended for multi-context mode, in single-context mode does nothing. + * + */ + public abstract void shutdown(); + + /** + * Sets mouse events preprocessor for event queue + */ + //public abstract void setMouseEventPreprocessor(MouseEventPreprocessor preprocessor); + + /** + * Create customized Choice using style + */ + //public abstract Choice createCustomChoice(ChoiceStyle style); + + //public abstract Insets getNativeInsets(Window w); + + /** + * Region to be repainted (could be null). Use this in overridden repaint() + */ + //public abstract MultiRectArea getRepaintRegion(Component c); + + //public abstract MultiRectArea subtractPendingRepaintRegion(Component c, MultiRectArea mra); + + /** + * Returns true if the window was at least once painted due to native paint events + */ + //public abstract boolean wasPainted(Window w); + + /** + * The component's region hidden behind top-level windows + * (belonging to both this Java app and all other apps), and behind + * heavyweight components overlapping with passed component + */ + //public abstract MultiRectArea getObscuredRegion(Component c); + + /** + * An accessor to Container.addObscuredRegions() method + * @see java.awt.Container#addObscuredRegions(MultiRectArea, Component) + */ + //public abstract void addObscuredRegions(MultiRectArea mra, Component c, Container container); + + /** + * Makes it possible to call protected Toolkit.setDesktopProperty() + * method from any class outside of java.awt package + */ + public abstract void setDesktopProperty(String name, Object value); + + /** + * Makes it possible to start/stop dialog modal loop + * from anywhere outside of java.awt package + */ + //public abstract void runModalLoop(Dialog dlg); + //public abstract void endModalLoop(Dialog dlg); + + /** + * Sets component's visible flag only + * (the component is not actually shown/hidden) + */ + //public abstract void setVisibleFlag(Component comp, boolean visible); + +} diff --git a/app/src/main/java/org/apache/harmony/awt/ContextStorage.java b/app/src/main/java/org/apache/harmony/awt/ContextStorage.java new file mode 100644 index 000000000..d44648aa3 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/ContextStorage.java @@ -0,0 +1,154 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package org.apache.harmony.awt; + +import java.awt.*; + +//???AWT +//import org.apache.harmony.awt.datatransfer.*; +import org.apache.harmony.awt.internal.nls.Messages; +import org.apache.harmony.awt.wtk.*; + + +public final class ContextStorage { + + private static volatile boolean multiContextMode = false; + private volatile boolean shutdownPending = false; + + private static final ContextStorage globalContext = new ContextStorage(); + + private Toolkit toolkit; + private ComponentInternals componentInternals; + //???AWT: private DTK dtk; + private WTK wtk; + private GraphicsEnvironment graphicsEnvironment; + + private class ContextLock {} + private final Object contextLock = new ContextLock(); + private final Synchronizer synchronizer = new Synchronizer(); + + public static void activateMultiContextMode() { + // TODO: checkPermission + multiContextMode = true; + } + + public static void setDefaultToolkit(Toolkit newToolkit) { + // TODO: checkPermission + getCurrentContext().toolkit = newToolkit; + } + + public static Toolkit getDefaultToolkit() { + return getCurrentContext().toolkit; + } + + //???AWT + /* + public static void setDTK(DTK dtk) { + // TODO: checkPermission + getCurrentContext().dtk = dtk; + } + + public static DTK getDTK() { + return getCurrentContext().dtk; + } + */ + + public static Synchronizer getSynchronizer() { + return getCurrentContext().synchronizer; + } + + public static ComponentInternals getComponentInternals() { + return getCurrentContext().componentInternals; + } + + static void setComponentInternals(ComponentInternals internals) { + // TODO: checkPermission + getCurrentContext().componentInternals = internals; + } + + public static Object getContextLock() { + return getCurrentContext().contextLock; + } + + public static WindowFactory getWindowFactory() { + return getCurrentContext().wtk.getWindowFactory(); + } + + public static void setWTK(WTK wtk) { + getCurrentContext().wtk = wtk; + } + + public static NativeIM getNativeIM() { + return getCurrentContext().wtk.getNativeIM(); + } + + public static NativeEventQueue getNativeEventQueue() { + return getCurrentContext().wtk.getNativeEventQueue(); + } + + public static GraphicsEnvironment getGraphicsEnvironment() { + return getCurrentContext().graphicsEnvironment; + } + + public static void setGraphicsEnvironment(GraphicsEnvironment environment) { + getCurrentContext().graphicsEnvironment = environment; + } + + private static ContextStorage getCurrentContext() { + return multiContextMode ? getContextThreadGroup().context : globalContext; + } + + private static ContextThreadGroup getContextThreadGroup() { + + Thread thread = Thread.currentThread(); + ThreadGroup group = thread.getThreadGroup(); + while (group != null) { + if (group instanceof ContextThreadGroup) { + return (ContextThreadGroup)group; + } + group = group.getParent(); + } + // awt.59=Application has run out of context thread group + throw new RuntimeException(Messages.getString("awt.59")); //$NON-NLS-1$ + } + + public static boolean shutdownPending() { + return getCurrentContext().shutdownPending; + } + + void shutdown() { + if (!multiContextMode) { + return; + } + shutdownPending = true; + + //???AWT: componentInternals.shutdown(); + + synchronized(contextLock) { + toolkit = null; + componentInternals = null; + //???AWT: dtk = null; + wtk = null; + graphicsEnvironment = null; + } + } + +} diff --git a/app/src/main/java/org/apache/harmony/awt/ContextThreadGroup.java b/app/src/main/java/org/apache/harmony/awt/ContextThreadGroup.java new file mode 100644 index 000000000..4f0af52fe --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/ContextThreadGroup.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package org.apache.harmony.awt; + +public class ContextThreadGroup extends ThreadGroup { + + final ContextStorage context = new ContextStorage(); + + public ContextThreadGroup(String name) { + super(name); + } + + public void dispose() { + context.shutdown(); + } +} diff --git a/app/src/main/java/org/apache/harmony/awt/ListenerList.java b/app/src/main/java/org/apache/harmony/awt/ListenerList.java new file mode 100644 index 000000000..f5c55f10a --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/ListenerList.java @@ -0,0 +1,194 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.awt; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EventListener; +import java.util.Iterator; +import java.util.List; + +/** + * List of AWT listeners. It is for 3 purposes. + * 1. To support list modification from listeners + * 2. To ensure call for all listeners as atomic operation + * 3. To support system listeners that are needed for built-in AWT components + */ +public class ListenerList implements Serializable { + private static final long serialVersionUID = 9180703263299648154L; + + private transient ArrayList systemList; + private transient ArrayList userList; + + public ListenerList() { + super(); + } + + /** + * Adds system listener to this list. + * + * @param listener - listener to be added. + */ + public void addSystemListener(T listener) { + if (systemList == null) { + systemList = new ArrayList(); + } + systemList.add(listener); + } + + /** + * Adds user (public) listener to this list. + * + * @param listener - listener to be added. + */ + public void addUserListener(T listener) { + if (listener == null) { + return; + } + // transactionally replace old list + synchronized (this) { + if (userList == null) { + userList = new ArrayList(); + userList.add(listener); + return; + } + ArrayList newList = new ArrayList(userList); + newList.add(listener); + userList = newList; + } + } + + /** + * Removes user (public) listener to this list. + * + * @param listener - listener to be removed. + */ + public void removeUserListener(Object listener) { + if (listener == null) { + return; + } + // transactionally replace old list + synchronized (this) { + if (userList == null || !userList.contains(listener)) { + return; + } + ArrayList newList = new ArrayList(userList); + newList.remove(listener); + userList = (newList.size() > 0 ? newList : null); + } + } + + /** + * Gets all user (public) listeners in one array. + * + * @param emptyArray - empty array, it's for deriving particular listeners class. + * @return array of all user listeners. + */ + public AT[] getUserListeners(AT[] emptyArray){ + synchronized (this) { + return (userList != null ? userList.toArray(emptyArray) : emptyArray); + + } + } + + /** + * Gets all user (public) listeners in one list. + * + * @return list of all user listeners. + */ + public List getUserListeners() { + synchronized (this) { + if (userList == null || userList.isEmpty()) { + return Collections.emptyList(); + } + return new ArrayList(userList); + } + } + + public List getSystemListeners() { + synchronized (this) { + if (systemList == null || systemList.isEmpty()) { + return Collections.emptyList(); + } + return new ArrayList(systemList); + } + } + + /** + * Gets iterator for user listeners. + * + * @return iterator for user listeners. + */ + public Iterator getUserIterator() { + synchronized (this) { + if (userList == null) { + List emptyList = Collections.emptyList(); + return emptyList.iterator(); + } + return new ReadOnlyIterator(userList.iterator()); + } + } + + /** + * Gets iterator for system listeners. + * + * @return iterator for system listeners. + */ + public Iterator getSystemIterator() { + return systemList.iterator(); + } + + private static ArrayList getOnlySerializable(ArrayList list) { + if (list == null) { + return null; + } + + ArrayList result = new ArrayList(); + for (Iterator it = list.iterator(); it.hasNext();) { + Object obj = it.next(); + if (obj instanceof Serializable) { + result.add(obj); + } + } + + return (result.size() != 0) ? result : null; + } + + private void writeObject(ObjectOutputStream stream) throws IOException { + + stream.defaultWriteObject(); + + stream.writeObject(getOnlySerializable(systemList)); + stream.writeObject(getOnlySerializable(userList)); + } + + @SuppressWarnings("unchecked") + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + + stream.defaultReadObject(); + + systemList = (ArrayList)stream.readObject(); + userList = (ArrayList)stream.readObject(); + } + +} diff --git a/app/src/main/java/org/apache/harmony/awt/ReadOnlyIterator.java b/app/src/main/java/org/apache/harmony/awt/ReadOnlyIterator.java new file mode 100644 index 000000000..671653fb9 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/ReadOnlyIterator.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package org.apache.harmony.awt; + +import java.util.Iterator; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * ReadOnlyIterator + */ +public final class ReadOnlyIterator implements Iterator { + + private final Iterator it; + + public ReadOnlyIterator(Iterator it) { + if (it == null) { + throw new NullPointerException(); + } + this.it = it; + } + + public void remove() { + // awt.50=Iterator is read-only + throw new UnsupportedOperationException(Messages.getString("awt.50")); //$NON-NLS-1$ + } + + public boolean hasNext() { + return it.hasNext(); + } + + public E next() { + return it.next(); + } +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/AwtImageBackdoorAccessor.java b/app/src/main/java/org/apache/harmony/awt/gl/AwtImageBackdoorAccessor.java new file mode 100644 index 000000000..bd5f6c680 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/AwtImageBackdoorAccessor.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + * Created on 23.11.2005 + * + */ + + +package org.apache.harmony.awt.gl; + +import java.awt.Image; +import java.awt.image.DataBuffer; +import java.awt.image.IndexColorModel; +import java.awt.image.DataBufferInt; + +import org.apache.harmony.awt.gl.image.DataBufferListener; + +/** + * This class give an opportunity to get access to private data of + * some java.awt.image classes + * Implementation of this class placed in java.awt.image package + */ + +public abstract class AwtImageBackdoorAccessor { + + static protected AwtImageBackdoorAccessor inst; + + public static AwtImageBackdoorAccessor getInstance(){ + // First we need to run the static initializer in the DataBuffer class to resolve inst. + new DataBufferInt(0); + return inst; + } + + public abstract Surface getImageSurface(Image image); + public abstract boolean isGrayPallete(IndexColorModel icm); + + public abstract Object getData(DataBuffer db); + public abstract int[] getDataInt(DataBuffer db); + public abstract byte[] getDataByte(DataBuffer db); + public abstract short[] getDataShort(DataBuffer db); + public abstract short[] getDataUShort(DataBuffer db); + public abstract double[] getDataDouble(DataBuffer db); + public abstract float[] getDataFloat(DataBuffer db); + public abstract void releaseData(DataBuffer db); + + public abstract void addDataBufferListener(DataBuffer db, DataBufferListener listener); + public abstract void removeDataBufferListener(DataBuffer db); + public abstract void validate(DataBuffer db); +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/CommonGraphics2D.java b/app/src/main/java/org/apache/harmony/awt/gl/CommonGraphics2D.java new file mode 100644 index 000000000..a33c38b3d --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/CommonGraphics2D.java @@ -0,0 +1,1132 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey A. Petrenko + * @version $Revision$ + */ +package org.apache.harmony.awt.gl; + + +import java.awt.AlphaComposite; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Paint; +import java.awt.PaintContext; +import java.awt.Point; +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.Toolkit; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.image.AffineTransformOp; +import java.awt.image.ImageObserver; +import java.awt.image.BufferedImage; +import java.awt.image.BufferedImageOp; +import java.awt.image.Raster; +import java.awt.image.RenderedImage; +import java.awt.image.WritableRaster; +import java.awt.image.renderable.RenderableImage; +import java.awt.geom.AffineTransform; +import java.awt.geom.Arc2D; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Line2D; +import java.awt.geom.PathIterator; +import java.awt.geom.RoundRectangle2D; +import java.text.AttributedCharacterIterator; +import java.util.Map; + +import org.apache.harmony.awt.gl.Surface; +import org.apache.harmony.awt.gl.image.OffscreenImage; +import org.apache.harmony.awt.gl.render.Blitter; +import org.apache.harmony.awt.gl.render.JavaArcRasterizer; +import org.apache.harmony.awt.gl.render.JavaLineRasterizer; +import org.apache.harmony.awt.gl.render.JavaShapeRasterizer; +import org.apache.harmony.awt.gl.render.JavaTextRenderer; +import org.apache.harmony.awt.gl.render.NullBlitter; + +/* + * List of abstract methods to implement in subclusses + * Graphics.copyArea(int x, int y, int width, int height, int dx, int dy) + * Graphics.create() + * Graphics2D.getDeviceConfiguration() + * CommonGraphics2D.fillMultiRectAreaColor(MultiRectArea mra); + * CommonGraphics2D.fillMultiRectAreaPaint(MultiRectArea mra); + */ + +/** + * CommonGraphics2D class is a super class for all system-dependent + * implementations. It implements major part of Graphics and Graphics2D + * abstract methods. + *

    CommonGraphics2D Class Internals

    + *

    Line and Shape Rasterizers

    + *

    + * The CommonGraphics2D class splits all shapes into a set of rectangles + * to unify the drawing process for different operating systems and architectures. + * For this purpose Java 2D* uses the JavaShapeRasterizer and the JavaLineRasterizer + * classes from the org.apache.harmony.awt.gl.render package. The JavaShapeRasterizer + * class splits an object implementing a Shape interface into a set of rectangles and + * produces a MultiRectArea object. The JavaLineRasterizer class makes line drawing + * more accurate and processes lines with strokes, which are instances of the BasicStroke + * class. + *

    + *

    + * To port the shape drawing to another platform you just need to override + * rectangle-drawing methods. However, if your operating system has functions to draw + * particular shapes, you can optimize your subclass of the CommonGraphics2D class by + * using this functionality in overridden methods. + *

    + + *

    Blitters

    + *

    + * Blitter classes draw images on the display or buffered images. All blitters inherit + * the org.apache.harmony.awt.gl.render.Blitter interface. + *

    + *

    Blitters are divided into: + *

      + *
    • Native blitters for simple types of images, which the underlying native library + * can draw.
    • + *
    • Java* blitters for those types of images, which the underlying native library + * cannot handle.
    • + *

    + *

    + * DRL Java 2D* also uses blitters to fill the shapes and the user-defined subclasses + * of the java.awt.Paint class with paints, which the system does not support. + *

    + * + *

    Text Renderers

    + *

    + *Text renderers draw strings and glyph vectors. All text renderers are subclasses + *of the org.apache.harmony.awt.gl.TextRenderer class. + *

    + * + */ +public abstract class CommonGraphics2D extends Graphics2D { + protected Surface dstSurf = null; + protected Blitter blitter = NullBlitter.getInstance(); + protected RenderingHints hints = new RenderingHints(null); + + // Clipping things + protected MultiRectArea clip = null; + + protected Paint paint = Color.WHITE; + protected Color fgColor = Color.WHITE; + protected Color bgColor = Color.BLACK; + + protected Composite composite = AlphaComposite.SrcOver; + + protected Stroke stroke = new BasicStroke(); + + //TODO: Think more about FontRenderContext + protected FontRenderContext frc = new FontRenderContext(null, false, false); + + protected JavaShapeRasterizer jsr = new JavaShapeRasterizer(); + + protected Font font = new Font("Dialog", Font.PLAIN, 12);; //$NON-NLS-1$ + + protected TextRenderer jtr = JavaTextRenderer.inst; + + // Current graphics transform + protected AffineTransform transform = new AffineTransform(); + protected double[] matrix = new double[6]; + + // Original user->device translation as transform and point + //public AffineTransform origTransform = new AffineTransform(); + public Point origPoint = new Point(0, 0); + + + // Print debug output or not + protected static final boolean debugOutput = "1".equals(System.getProperty("g2d.debug")); //$NON-NLS-1$ //$NON-NLS-2$ + + // Constructors + protected CommonGraphics2D() { + } + + protected CommonGraphics2D(int tx, int ty) { + this(tx, ty, null); + } + + protected CommonGraphics2D(int tx, int ty, MultiRectArea clip) { + setTransform(AffineTransform.getTranslateInstance(tx, ty)); + //origTransform = AffineTransform.getTranslateInstance(tx, ty); + origPoint = new Point(tx, ty); + setClip(clip); + } + + // Public methods + @Override + public void addRenderingHints(Map hints) { + this.hints.putAll(hints); + } + + @Override + public void clearRect(int x, int y, int width, int height) { + Color c = getColor(); + Paint p = getPaint(); + setColor(getBackground()); + fillRect(x, y, width, height); + setColor(c); + setPaint(p); + if (debugOutput) { + System.err.println("CommonGraphics2D.clearRect("+x+", "+y+", "+width+", "+height+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ + } + } + + @Override + public void clipRect(int x, int y, int width, int height) { + clip(new Rectangle(x, y, width, height)); + } + + + @Override + public void clip(Shape s) { + if (s == null) { + clip = null; + return; + } + + MultiRectArea mra = null; + if (s instanceof MultiRectArea) { + mra = new MultiRectArea((MultiRectArea)s); + mra.translate((int)transform.getTranslateX(), (int)transform.getTranslateY()); + } else { + int type = transform.getType(); + if(s instanceof Rectangle && (type & (AffineTransform.TYPE_IDENTITY | + AffineTransform.TYPE_TRANSLATION)) != 0){ + mra = new MultiRectArea((Rectangle)s); + if(type == AffineTransform.TYPE_TRANSLATION){ + mra.translate((int)transform.getTranslateX(), (int)transform.getTranslateY()); + } + } else { + s = transform.createTransformedShape(s); + mra = jsr.rasterize(s, 0.5); + } + } + + if (clip == null) { + setTransformedClip(mra); + } else { + clip.intersect(mra); + setTransformedClip(clip); + } + } + + @Override + public void dispose() { + // Do nothing for Java only classes + } + + + + + /*************************************************************************** + * + * Draw methods + * + ***************************************************************************/ + + @Override + public void draw(Shape s) { + if (stroke instanceof BasicStroke && ((BasicStroke)stroke).getLineWidth() <= 1) { + //TODO: Think about drawing the shape in one fillMultiRectArea call + BasicStroke bstroke = (BasicStroke)stroke; + JavaLineRasterizer.LineDasher ld = (bstroke.getDashArray() == null)?null:new JavaLineRasterizer.LineDasher(bstroke.getDashArray(), bstroke.getDashPhase()); + PathIterator pi = s.getPathIterator(transform, 0.5); + float []points = new float[6]; + int x1 = Integer.MIN_VALUE; + int y1 = Integer.MIN_VALUE; + int cx1 = Integer.MIN_VALUE; + int cy1 = Integer.MIN_VALUE; + while (!pi.isDone()) { + switch (pi.currentSegment(points)) { + case PathIterator.SEG_MOVETO: + x1 = (int)Math.floor(points[0]); + y1 = (int)Math.floor(points[1]); + cx1 = x1; + cy1 = y1; + break; + case PathIterator.SEG_LINETO: + int x2 = (int)Math.floor(points[0]); + int y2 = (int)Math.floor(points[1]); + fillMultiRectArea(JavaLineRasterizer.rasterize(x1, y1, x2, y2, null, ld, false)); + x1 = x2; + y1 = y2; + break; + case PathIterator.SEG_CLOSE: + x2 = cx1; + y2 = cy1; + fillMultiRectArea(JavaLineRasterizer.rasterize(x1, y1, x2, y2, null, ld, false)); + x1 = x2; + y1 = y2; + break; + } + pi.next(); + } + } else { + s = stroke.createStrokedShape(s); + s = transform.createTransformedShape(s); + fillMultiRectArea(jsr.rasterize(s, 0.5)); + } + } + + @Override + public void drawArc(int x, int y, int width, int height, int sa, int ea) { + if (stroke instanceof BasicStroke && ((BasicStroke)stroke).getLineWidth() <= 1 && + ((BasicStroke)stroke).getDashArray() == null && + (transform.isIdentity() || transform.getType() == AffineTransform.TYPE_TRANSLATION)) { + Point p = new Point(x, y); + transform.transform(p, p); + MultiRectArea mra = JavaArcRasterizer.rasterize(x, y, width, height, sa, ea, clip); + fillMultiRectArea(mra); + return; + } + draw(new Arc2D.Float(x, y, width, height, sa, ea, Arc2D.OPEN)); + } + + + @Override + public boolean drawImage(Image image, int x, int y, Color bgcolor, + ImageObserver imageObserver) { + + if(image == null) { + return true; + } + + boolean done = false; + boolean somebits = false; + Surface srcSurf = null; + if(image instanceof OffscreenImage){ + OffscreenImage oi = (OffscreenImage) image; + if((oi.getState() & ImageObserver.ERROR) != 0) { + return false; + } + done = oi.prepareImage(imageObserver); + somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0; + srcSurf = oi.getImageSurface(); + }else{ + done = true; + srcSurf = Surface.getImageSurface(image); + } + + if(done || somebits) { + int w = srcSurf.getWidth(); + int h = srcSurf.getHeight(); + blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h, (AffineTransform) transform.clone(), + composite, bgcolor, clip); + } + return done; + } + + @Override + public boolean drawImage(Image image, int x, int y, ImageObserver imageObserver) { + return drawImage(image, x, y, null, imageObserver); + } + + @Override + public boolean drawImage(Image image, int x, int y, int width, int height, + Color bgcolor, ImageObserver imageObserver) { + + if(image == null) { + return true; + } + if(width == 0 || height == 0) { + return true; + } + + boolean done = false; + boolean somebits = false; + Surface srcSurf = null; + + if(image instanceof OffscreenImage){ + OffscreenImage oi = (OffscreenImage) image; + if((oi.getState() & ImageObserver.ERROR) != 0) { + return false; + } + done = oi.prepareImage(imageObserver); + somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0; + srcSurf = oi.getImageSurface(); + }else{ + done = true; + srcSurf = Surface.getImageSurface(image); + } + + if(done || somebits) { + int w = srcSurf.getWidth(); + int h = srcSurf.getHeight(); + if(w == width && h == height){ + blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h, + (AffineTransform) transform.clone(), + composite, bgcolor, clip); + }else{ + AffineTransform xform = new AffineTransform(); + xform.setToScale((float)width / w, (float)height / h); + blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h, + (AffineTransform) transform.clone(), + xform, composite, bgcolor, clip); + } + } + return done; + } + + @Override + public boolean drawImage(Image image, int x, int y, int width, int height, + ImageObserver imageObserver) { + return drawImage(image, x, y, width, height, null, imageObserver); + } + + @Override + public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, Color bgcolor, + ImageObserver imageObserver) { + + if(image == null) { + return true; + } + if(dx1 == dx2 || dy1 == dy2 || sx1 == sx2 || sy1 == sy2) { + return true; + } + + boolean done = false; + boolean somebits = false; + Surface srcSurf = null; + if(image instanceof OffscreenImage){ + OffscreenImage oi = (OffscreenImage) image; + if((oi.getState() & ImageObserver.ERROR) != 0) { + return false; + } + done = oi.prepareImage(imageObserver); + somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0; + srcSurf = oi.getImageSurface(); + }else{ + done = true; + srcSurf = Surface.getImageSurface(image); + } + + if(done || somebits) { + + int dstX = dx1; + int dstY = dy1; + int srcX = sx1; + int srcY = sy1; + + int dstW = dx2 - dx1; + int dstH = dy2 - dy1; + int srcW = sx2 - sx1; + int srcH = sy2 - sy1; + + if(srcW == dstW && srcH == dstH){ + blitter.blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, srcW, srcH, + (AffineTransform) transform.clone(), + composite, bgcolor, clip); + }else{ + AffineTransform xform = new AffineTransform(); + xform.setToScale((float)dstW / srcW, (float)dstH / srcH); + blitter.blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, srcW, srcH, + (AffineTransform) transform.clone(), + xform, composite, bgcolor, clip); + } + } + return done; + } + + @Override + public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, ImageObserver imageObserver) { + + return drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null, + imageObserver); + } + + @Override + public void drawImage(BufferedImage bufImage, BufferedImageOp op, + int x, int y) { + + if(bufImage == null) { + return; + } + + if(op == null) { + drawImage(bufImage, x, y, null); + } else if(op instanceof AffineTransformOp){ + AffineTransformOp atop = (AffineTransformOp) op; + AffineTransform xform = atop.getTransform(); + Surface srcSurf = Surface.getImageSurface(bufImage); + int w = srcSurf.getWidth(); + int h = srcSurf.getHeight(); + blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h, + (AffineTransform) transform.clone(), xform, + composite, null, clip); + } else { + bufImage = op.filter(bufImage, null); + Surface srcSurf = Surface.getImageSurface(bufImage); + int w = srcSurf.getWidth(); + int h = srcSurf.getHeight(); + blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h, + (AffineTransform) transform.clone(), + composite, null, clip); + } + } + + @Override + public boolean drawImage(Image image, AffineTransform trans, + ImageObserver imageObserver) { + + if(image == null) { + return true; + } + if(trans == null || trans.isIdentity()) { + return drawImage(image, 0, 0, imageObserver); + } + + boolean done = false; + boolean somebits = false; + Surface srcSurf = null; + if(image instanceof OffscreenImage){ + OffscreenImage oi = (OffscreenImage) image; + if((oi.getState() & ImageObserver.ERROR) != 0) { + return false; + } + done = oi.prepareImage(imageObserver); + somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0; + srcSurf = oi.getImageSurface(); + }else{ + done = true; + srcSurf = Surface.getImageSurface(image); + } + + if(done || somebits) { + int w = srcSurf.getWidth(); + int h = srcSurf.getHeight(); + AffineTransform xform = (AffineTransform) transform.clone(); + xform.concatenate(trans); + blitter.blit(0, 0, srcSurf, 0, 0, dstSurf, w, h, xform, composite, + null, clip); + } + return done; + } + + @Override + public void drawLine(int x1, int y1, int x2, int y2) { + if (debugOutput) { + System.err.println("CommonGraphics2D.drawLine("+x1+", "+y1+", "+x2+", "+y2+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ + } + + if (stroke instanceof BasicStroke && ((BasicStroke)stroke).getLineWidth() <= 1) { + BasicStroke bstroke = (BasicStroke)stroke; + Point p1 = new Point(x1, y1); + Point p2 = new Point(x2, y2); + transform.transform(p1, p1); + transform.transform(p2, p2); + JavaLineRasterizer.LineDasher ld = (bstroke.getDashArray() == null)?null:new JavaLineRasterizer.LineDasher(bstroke.getDashArray(), bstroke.getDashPhase()); + MultiRectArea mra = JavaLineRasterizer.rasterize(p1.x, p1.y, p2.x, p2.y, null, ld, false); + fillMultiRectArea(mra); + return; + } + draw(new Line2D.Float(x1, y1, x2, y2)); + } + + @Override + public void drawOval(int x, int y, int width, int height) { + if (stroke instanceof BasicStroke && ((BasicStroke)stroke).getLineWidth() <= 1 && + ((BasicStroke)stroke).getDashArray() == null && + (transform.isIdentity() || transform.getType() == AffineTransform.TYPE_TRANSLATION)) { + Point p = new Point(x, y); + transform.transform(p, p); + MultiRectArea mra = JavaArcRasterizer.rasterize(x, y, width, height, 0, 360, clip); + fillMultiRectArea(mra); + return; + } + draw(new Ellipse2D.Float(x, y, width, height)); + } + + @Override + public void drawPolygon(int[] xpoints, int[] ypoints, int npoints) { + draw(new Polygon(xpoints, ypoints, npoints)); + } + + @Override + public void drawPolygon(Polygon polygon) { + draw(polygon); + } + + @Override + public void drawPolyline(int[] xpoints, int[] ypoints, int npoints) { + for (int i = 0; i < npoints-1; i++) { + drawLine(xpoints[i], ypoints[i], xpoints[i+1], ypoints[i+1]); + } + } + + @Override + public void drawRenderableImage(RenderableImage img, AffineTransform xform) { + if (img == null) { + return; + } + + double scaleX = xform.getScaleX(); + double scaleY = xform.getScaleY(); + if (scaleX == 1 && scaleY == 1) { + drawRenderedImage(img.createDefaultRendering(), xform); + } else { + int width = (int)Math.round(img.getWidth()*scaleX); + int height = (int)Math.round(img.getHeight()*scaleY); + xform = (AffineTransform)xform.clone(); + xform.scale(1, 1); + drawRenderedImage(img.createScaledRendering(width, height, null), xform); + } + } + + @Override + public void drawRenderedImage(RenderedImage rimg, AffineTransform xform) { + if (rimg == null) { + return; + } + + Image img = null; + + if (rimg instanceof Image) { + img = (Image)rimg; + } else { + //TODO: Create new class to provide Image interface for RenderedImage or rewrite this method + img = new BufferedImage(rimg.getColorModel(), rimg.copyData(null), false, null); + } + + drawImage(img, xform, null); + } + + @Override + public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { + if (debugOutput) { + System.err.println("CommonGraphics2D.drawRoundRect("+x+", "+y+", "+width+", "+height+","+arcWidth+", "+arcHeight+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ + } + + draw(new RoundRectangle2D.Float(x, y, width, height, arcWidth, arcHeight)); + } + + + + + + /*************************************************************************** + * + * String methods + * + ***************************************************************************/ + + @Override + public void drawString(AttributedCharacterIterator iterator, float x, float y) { + GlyphVector gv = font.createGlyphVector(frc, iterator); + drawGlyphVector(gv, x, y); + } + + @Override + public void drawString(AttributedCharacterIterator iterator, int x, int y) { + drawString(iterator, (float)x, (float)y); + } + + @Override + public void drawString(String str, int x, int y) { + drawString(str, (float)x, (float)y); + } + + @Override + public void drawString(String str, float x, float y) { + if (debugOutput) { + System.err.println("CommonGraphics2D.drawString("+str+", "+x+", "+y+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + } + + AffineTransform at = (AffineTransform)this.getTransform().clone(); + AffineTransform fontTransform = font.getTransform(); + at.concatenate(fontTransform); + + double[] matrix = new double[6]; + if (!at.isIdentity()){ + + int atType = at.getType(); + at.getMatrix(matrix); + + // TYPE_TRANSLATION + if (atType == AffineTransform.TYPE_TRANSLATION){ + jtr.drawString(this, str, + (float)(x+fontTransform.getTranslateX()), + (float)(y+fontTransform.getTranslateY())); + return; + } + // TODO: we use slow type of drawing strings when Font object + // in Graphics has transforms, we just fill outlines. New textrenderer + // is to be implemented. + Shape sh = font.createGlyphVector(this.getFontRenderContext(), str).getOutline(x, y); + this.fill(sh); + + } else { + jtr.drawString(this, str, x, y); + } + + } + + @Override + public void drawGlyphVector(GlyphVector gv, float x, float y) { + + AffineTransform at = gv.getFont().getTransform(); + + double[] matrix = new double[6]; + if ((at != null) && (!at.isIdentity())){ + + int atType = at.getType(); + at.getMatrix(matrix); + + // TYPE_TRANSLATION + if ((atType == AffineTransform.TYPE_TRANSLATION) && + ((gv.getLayoutFlags() & GlyphVector.FLAG_HAS_TRANSFORMS) == 0)){ + jtr.drawGlyphVector(this, gv, (int)(x+matrix[4]), (int)(y+matrix[5])); + return; + } + } else { + if (((gv.getLayoutFlags() & GlyphVector.FLAG_HAS_TRANSFORMS) == 0)){ + jtr.drawGlyphVector(this, gv, x, y); + return; + } + } + + // TODO: we use slow type of drawing strings when Font object + // in Graphics has transforms, we just fill outlines. New textrenderer + // is to be implemented. + + Shape sh = gv.getOutline(x, y); + this.fill(sh); + + } + + + + + /*************************************************************************** + * + * Fill methods + * + ***************************************************************************/ + + @Override + public void fill(Shape s) { + s = transform.createTransformedShape(s); + MultiRectArea mra = jsr.rasterize(s, 0.5); + fillMultiRectArea(mra); + } + + @Override + public void fillArc(int x, int y, int width, int height, int sa, int ea) { + fill(new Arc2D.Float(x, y, width, height, sa, ea, Arc2D.PIE)); + } + + @Override + public void fillOval(int x, int y, int width, int height) { + fill(new Ellipse2D.Float(x, y, width, height)); + } + + @Override + public void fillPolygon(int[] xpoints, int[] ypoints, int npoints) { + fill(new Polygon(xpoints, ypoints, npoints)); + } + + @Override + public void fillPolygon(Polygon polygon) { + fill(polygon); + } + + @Override + public void fillRect(int x, int y, int width, int height) { + if (debugOutput) { + System.err.println("CommonGraphics2D.fillRect("+x+", "+y+", "+width+", "+height+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ + } + + fill(new Rectangle(x, y, width, height)); + } + + @Override + public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { + if (debugOutput) { + System.err.println("CommonGraphics2D.fillRoundRect("+x+", "+y+", "+width+", "+height+","+arcWidth+", "+arcHeight+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ + } + + fill(new RoundRectangle2D.Float(x, y, width, height, arcWidth, arcHeight)); + } + + + + + /*************************************************************************** + * + * Get methods + * + ***************************************************************************/ + + @Override + public Color getBackground() { + return bgColor; + } + + @Override + public Shape getClip() { + if (clip == null) { + return null; + } + + MultiRectArea res = new MultiRectArea(clip); + res.translate(-Math.round((float)transform.getTranslateX()), -Math.round((float)transform.getTranslateY())); + return res; + } + + @Override + public Rectangle getClipBounds() { + if (clip == null) { + return null; + } + + Rectangle res = (Rectangle) clip.getBounds().clone(); + res.translate(-Math.round((float)transform.getTranslateX()), -Math.round((float)transform.getTranslateY())); + return res; + } + + @Override + public Color getColor() { + return fgColor; + } + + @Override + public Composite getComposite() { + return composite; + } + + @Override + public Font getFont() { + return font; + } + + @SuppressWarnings("deprecation") + @Override + public FontMetrics getFontMetrics(Font font) { + return Toolkit.getDefaultToolkit().getFontMetrics(font); + } + + @Override + public FontRenderContext getFontRenderContext() { + return frc; + } + + @Override + public Paint getPaint() { + return paint; + } + + @Override + public Object getRenderingHint(RenderingHints.Key key) { + return hints.get(key); + } + + @Override + public RenderingHints getRenderingHints() { + return hints; + } + + @Override + public Stroke getStroke() { + return stroke; + } + + @Override + public AffineTransform getTransform() { + return (AffineTransform)transform.clone(); + } + + @Override + public boolean hit(Rectangle rect, Shape s, boolean onStroke) { + //TODO: Implement method.... + return false; + } + + + + + /*************************************************************************** + * + * Transformation methods + * + ***************************************************************************/ + + @Override + public void rotate(double theta) { + transform.rotate(theta); + transform.getMatrix(matrix); + } + + @Override + public void rotate(double theta, double x, double y) { + transform.rotate(theta, x, y); + transform.getMatrix(matrix); + } + + @Override + public void scale(double sx, double sy) { + transform.scale(sx, sy); + transform.getMatrix(matrix); + } + + @Override + public void shear(double shx, double shy) { + transform.shear(shx, shy); + transform.getMatrix(matrix); + } + + @Override + public void transform(AffineTransform at) { + transform.concatenate(at); + transform.getMatrix(matrix); + } + + @Override + public void translate(double tx, double ty) { + if (debugOutput) { + System.err.println("CommonGraphics2D.translate("+tx+", "+ty+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + transform.translate(tx, ty); + transform.getMatrix(matrix); + } + + @Override + public void translate(int tx, int ty) { + if (debugOutput) { + System.err.println("CommonGraphics2D.translate("+tx+", "+ty+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + transform.translate(tx, ty); + transform.getMatrix(matrix); + } + + + + + /*************************************************************************** + * + * Set methods + * + ***************************************************************************/ + + @Override + public void setBackground(Color color) { + bgColor = color; + } + + @Override + public void setClip(int x, int y, int width, int height) { + setClip(new Rectangle(x, y, width, height)); + } + + @Override + public void setClip(Shape s) { + if (s == null) { + setTransformedClip(null); + if (debugOutput) { + System.err.println("CommonGraphics2D.setClip(null)"); //$NON-NLS-1$ + } + return; + } + + if (debugOutput) { + System.err.println("CommonGraphics2D.setClip("+s.getBounds()+")"); //$NON-NLS-1$ //$NON-NLS-2$ + } + + if (s instanceof MultiRectArea) { + MultiRectArea nclip = new MultiRectArea((MultiRectArea)s); + nclip.translate(Math.round((float)transform.getTranslateX()), Math.round((float)transform.getTranslateY())); + setTransformedClip(nclip); + } else { + int type = transform.getType(); + if(s instanceof Rectangle && (type & (AffineTransform.TYPE_IDENTITY | + AffineTransform.TYPE_TRANSLATION)) != 0){ + MultiRectArea nclip = new MultiRectArea((Rectangle)s); + if(type == AffineTransform.TYPE_TRANSLATION){ + nclip.translate((int)transform.getTranslateX(), (int)transform.getTranslateY()); + } + setTransformedClip(nclip); + } else { + s = transform.createTransformedShape(s); + setTransformedClip(jsr.rasterize(s, 0.5)); + } + } + } + + @Override + public void setColor(Color color) { + if (color != null) { + fgColor = color; + paint = color; + } + } + + @Override + public void setComposite(Composite composite) { + this.composite = composite; + } + + @Override + public void setFont(Font font) { + this.font = font; + } + + @Override + public void setPaint(Paint paint) { + if (paint == null) + return; + + this.paint = paint; + if (paint instanceof Color) { + fgColor = (Color)paint; + } + } + + @Override + public void setPaintMode() { + composite = AlphaComposite.SrcOver; + } + + @Override + public void setRenderingHint(RenderingHints.Key key, Object value) { + hints.put(key, value); + } + + @Override + public void setRenderingHints(Map hints) { + this.hints.clear(); + this.hints.putAll(hints); + } + + @Override + public void setStroke(Stroke stroke) { + this.stroke = stroke; + } + + @Override + public void setTransform(AffineTransform transform) { + this.transform = transform; + + transform.getMatrix(matrix); + } + + @Override + public void setXORMode(Color color) { + composite = new XORComposite(color); + } + + + // Protected methods + protected void setTransformedClip(MultiRectArea clip) { + this.clip = clip; + } + + /** + * This method fills the given MultiRectArea with current paint. + * It calls fillMultiRectAreaColor and fillMultiRectAreaPaint + * methods depending on the type of current paint. + * @param mra MultiRectArea to fill + */ + protected void fillMultiRectArea(MultiRectArea mra) { + if (clip != null) { + mra.intersect(clip); + } + + // Return if all stuff is clipped + if (mra.rect[0] < 5) { + return; + } + + if (debugOutput) { + System.err.println("CommonGraphics2D.fillMultiRectArea("+mra+")"); //$NON-NLS-1$ //$NON-NLS-2$ + } + + if (paint instanceof Color){ + fillMultiRectAreaColor(mra); + }else{ + fillMultiRectAreaPaint(mra); + } + } + + /** + * This method fills the given MultiRectArea with solid color. + * @param mra MultiRectArea to fill + */ + protected void fillMultiRectAreaColor(MultiRectArea mra) { + fillMultiRectAreaPaint(mra); + } + + /** + * This method fills the given MultiRectArea with any paint. + * @param mra MultiRectArea to fill + */ + protected void fillMultiRectAreaPaint(MultiRectArea mra) { + Rectangle rec = mra.getBounds(); + int x = rec.x; + int y = rec.y; + int w = rec.width; + int h = rec.height; + if(w <= 0 || h <= 0) { + return; + } + PaintContext pc = paint.createContext(null, rec, rec, transform, hints); + Raster r = pc.getRaster(x, y, w, h); + WritableRaster wr; + if(r instanceof WritableRaster){ + wr = (WritableRaster) r; + }else{ + wr = r.createCompatibleWritableRaster(); + wr.setRect(r); + } + Surface srcSurf = new ImageSurface(pc.getColorModel(), wr); + blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h, + composite, null, mra); + srcSurf.dispose(); + } + + /** + * Copies graphics class fields. + * Used in create method + * + * @param copy Graphics class to copy + */ + protected void copyInternalFields(CommonGraphics2D copy) { + if (clip == null) { + copy.setTransformedClip(null); + } else { + copy.setTransformedClip(new MultiRectArea(clip)); + } + copy.setBackground(bgColor); + copy.setColor(fgColor); + copy.setPaint(paint); + copy.setComposite(composite); + copy.setStroke(stroke); + copy.setFont(font); + copy.setTransform(new AffineTransform(transform)); + //copy.origTransform = new AffineTransform(origTransform); + copy.origPoint = new Point(origPoint); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/apache/harmony/awt/gl/CommonGraphics2DFactory.java b/app/src/main/java/org/apache/harmony/awt/gl/CommonGraphics2DFactory.java new file mode 100644 index 000000000..5c2d032cb --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/CommonGraphics2DFactory.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey A. Petrenko, Ilya S. Okomin + * @version $Revision$ + */ +package org.apache.harmony.awt.gl; + +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.peer.FontPeer; + +import org.apache.harmony.awt.gl.font.FontMetricsImpl; +import org.apache.harmony.awt.wtk.GraphicsFactory; + +/** + * Common GraphicsFactory implementation + * + */ +public abstract class CommonGraphics2DFactory implements GraphicsFactory { + + // static instance of CommonGraphics2DFactory + public static CommonGraphics2DFactory inst; + + /** + * Returns FontMetrics object that keeps metrics of the specified font. + * + * @param font specified Font + * @return FontMetrics object corresponding to the specified Font object + */ + public FontMetrics getFontMetrics(Font font) { + FontMetrics fm; + for (FontMetrics element : cacheFM) { + fm = element; + if (fm == null){ + break; + } + + if (fm.getFont().equals(font)){ + return fm; + } + } + fm = new FontMetricsImpl(font); + + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(cacheFM, 0, cacheFM, 1, cacheFM.length -1); + cacheFM[0] = fm; + + return fm; + } + // Font methods + + public FontPeer getFontPeer(Font font) { + return getFontManager().getFontPeer(font.getName(), font.getStyle(), font.getSize()); + } + + /** + * Embeds font from gile with specified path into the system. + * + * @param fontFilePath path to the font file + * @return Font object that was created from the file. + */ + public abstract Font embedFont(String fontFilePath); + +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/CommonGraphicsEnvironment.java b/app/src/main/java/org/apache/harmony/awt/gl/CommonGraphicsEnvironment.java new file mode 100644 index 000000000..5c78e50d5 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/CommonGraphicsEnvironment.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey A. Petrenko, Oleg V. Khaschansky + * @version $Revision$ + */ +package org.apache.harmony.awt.gl; + +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.GraphicsEnvironment; +import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.Locale; + +import org.apache.harmony.awt.gl.image.BufferedImageGraphics2D; + +/** + * Common GraphicsEnvironment implementation + * + */ +public abstract class CommonGraphicsEnvironment extends GraphicsEnvironment { + + @Override + public Graphics2D createGraphics(BufferedImage bufferedImage) { + return new BufferedImageGraphics2D(bufferedImage); + } + + @Override + public String[] getAvailableFontFamilyNames(Locale locale) { + Font[] fonts = getAllFonts(); + ArrayList familyNames = new ArrayList(); + + for (Font element : fonts) { + String name = element.getFamily(locale); + if (!familyNames.contains(name)) { + familyNames.add(name); + } + } + + return familyNames.toArray(new String[familyNames.size()]); + } + + @Override + public Font[] getAllFonts() { + return CommonGraphics2DFactory.inst.getFontManager().getAllFonts(); + } + + @Override + public String[] getAvailableFontFamilyNames() { + return CommonGraphics2DFactory.inst.getFontManager().getAllFamilies(); + } +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/GLVolatileImage.java b/app/src/main/java/org/apache/harmony/awt/gl/GLVolatileImage.java new file mode 100644 index 000000000..177be2309 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/GLVolatileImage.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package org.apache.harmony.awt.gl; + +import java.awt.image.*; + +import org.apache.harmony.awt.gl.Surface; + +public abstract class GLVolatileImage extends VolatileImage { + + public abstract Surface getImageSurface(); +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/ICompositeContext.java b/app/src/main/java/org/apache/harmony/awt/gl/ICompositeContext.java new file mode 100644 index 000000000..fc5631f37 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/ICompositeContext.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +package org.apache.harmony.awt.gl; + +import java.awt.Composite; +import java.awt.CompositeContext; +import java.awt.image.ColorModel; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; + +import org.apache.harmony.awt.gl.ImageSurface; +import org.apache.harmony.awt.gl.render.NativeImageBlitter; +import org.apache.harmony.awt.internal.nls.Messages; + + +/** + * This class represent implementation of the CompositeContext interface + */ +public class ICompositeContext implements CompositeContext { + Composite composite; + ColorModel srcCM, dstCM; + ImageSurface srcSurf, dstSurf; + + public ICompositeContext(Composite comp, ColorModel src, ColorModel dst){ + composite = comp; + srcCM = src; + dstCM = dst; + } + + public void dispose() { + srcSurf.dispose(); + dstSurf.dispose(); + } + + public void compose(Raster srcIn, Raster dstIn, WritableRaster dstOut) { + + if(!srcCM.isCompatibleRaster(srcIn)) { + // awt.48=The srcIn raster is incompatible with src ColorModel + throw new IllegalArgumentException(Messages.getString("awt.48")); //$NON-NLS-1$ + } + + if(!dstCM.isCompatibleRaster(dstIn)) { + // awt.49=The dstIn raster is incompatible with dst ColorModel + throw new IllegalArgumentException(Messages.getString("awt.49")); //$NON-NLS-1$ + } + + if(dstIn != dstOut){ + if(!dstCM.isCompatibleRaster(dstOut)) { + // awt.4A=The dstOut raster is incompatible with dst ColorModel + throw new IllegalArgumentException(Messages.getString("awt.4A")); //$NON-NLS-1$ + } + dstOut.setDataElements(0, 0, dstIn); + } + WritableRaster src; + if(srcIn instanceof WritableRaster){ + src = (WritableRaster) srcIn; + }else{ + src = srcIn.createCompatibleWritableRaster(); + src.setDataElements(0, 0, srcIn); + } + srcSurf = new ImageSurface(srcCM, src); + dstSurf = new ImageSurface(dstCM, dstOut); + + int w = Math.min(srcIn.getWidth(), dstOut.getWidth()); + int h = Math.min(srcIn.getHeight(), dstOut.getHeight()); + + NativeImageBlitter.getInstance().blit(0, 0, srcSurf, 0, 0, dstSurf, + w, h, composite, null, null); + + } + +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/ImageSurface.java b/app/src/main/java/org/apache/harmony/awt/gl/ImageSurface.java new file mode 100644 index 000000000..6368dd876 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/ImageSurface.java @@ -0,0 +1,323 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + * Created on 10.11.2005 + * + */ +package org.apache.harmony.awt.gl; + +import java.awt.color.ColorSpace; +import java.awt.image.BandedSampleModel; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.ComponentColorModel; +import java.awt.image.ComponentSampleModel; +import java.awt.image.DirectColorModel; +import java.awt.image.IndexColorModel; +import java.awt.image.MultiPixelPackedSampleModel; +import java.awt.image.PixelInterleavedSampleModel; +import java.awt.image.SampleModel; +import java.awt.image.SinglePixelPackedSampleModel; +import java.awt.image.WritableRaster; + +import org.apache.harmony.awt.gl.color.LUTColorConverter; +import org.apache.harmony.awt.gl.image.DataBufferListener; +import org.apache.harmony.awt.internal.nls.Messages; + + +/** + * This class represent Surface for different types of Images (BufferedImage, + * OffscreenImage and so on) + */ +public class ImageSurface extends Surface implements DataBufferListener { + + boolean nativeDrawable = true; + int surfaceType; + int csType; + ColorModel cm; + WritableRaster raster; + Object data; + + boolean needToRefresh = true; + boolean dataTaken = false; + + private long cachedDataPtr; // Pointer for cached Image Data + private boolean alphaPre; // Cached Image Data alpha premultiplied + + public ImageSurface(ColorModel cm, WritableRaster raster){ + this(cm, raster, Surface.getType(cm, raster)); + } + + public ImageSurface(ColorModel cm, WritableRaster raster, int type){ + if (!cm.isCompatibleRaster(raster)) { + // awt.4D=The raster is incompatible with this ColorModel + throw new IllegalArgumentException(Messages.getString("awt.4D")); //$NON-NLS-1$ + } + this.cm = cm; + this.raster = raster; + surfaceType = type; + + data = AwtImageBackdoorAccessor.getInstance(). + getData(raster.getDataBuffer()); + ColorSpace cs = cm.getColorSpace(); + transparency = cm.getTransparency(); + width = raster.getWidth(); + height = raster.getHeight(); + + // For the moment we can build natively only images which have + // sRGB, Linear_RGB, Linear_Gray Color Space and type different + // from BufferedImage.TYPE_CUSTOM + if(cs == LUTColorConverter.sRGB_CS){ + csType = sRGB_CS; + }else if(cs == LUTColorConverter.LINEAR_RGB_CS){ + csType = Linear_RGB_CS; + }else if(cs == LUTColorConverter.LINEAR_GRAY_CS){ + csType = Linear_Gray_CS; + }else{ + csType = Custom_CS; + nativeDrawable = false; + } + + if(type == BufferedImage.TYPE_CUSTOM){ + nativeDrawable = false; + } + } + + @Override + public ColorModel getColorModel() { + return cm; + } + + @Override + public WritableRaster getRaster() { + return raster; + } + + @Override + public long getSurfaceDataPtr() { + if(surfaceDataPtr == 0L && nativeDrawable){ + createSufaceStructure(); + } + return surfaceDataPtr; + } + + @Override + public Object getData(){ + return data; + } + + @Override + public boolean isNativeDrawable(){ + return nativeDrawable; + } + + @Override + public int getSurfaceType() { + return surfaceType; + } + + /** + * Creates native Surface structure which used for native blitting + */ + private void createSufaceStructure(){ + int cmType = 0; + int numComponents = cm.getNumComponents(); + boolean hasAlpha = cm.hasAlpha(); + boolean isAlphaPre = cm.isAlphaPremultiplied(); + int transparency = cm.getTransparency(); + int bits[] = cm.getComponentSize(); + int pixelStride = cm.getPixelSize(); + int masks[] = null; + int colorMap[] = null; + int colorMapSize = 0; + int transpPixel = -1; + boolean isGrayPallete = false; + SampleModel sm = raster.getSampleModel(); + int smType = 0; + int dataType = sm.getDataType(); + int scanlineStride = 0; + int bankIndeces[] = null; + int bandOffsets[] = null; + int offset = raster.getDataBuffer().getOffset(); + + if(cm instanceof DirectColorModel){ + cmType = DCM; + DirectColorModel dcm = (DirectColorModel) cm; + masks = dcm.getMasks(); + smType = SPPSM; + SinglePixelPackedSampleModel sppsm = (SinglePixelPackedSampleModel) sm; + scanlineStride = sppsm.getScanlineStride(); + + }else if(cm instanceof IndexColorModel){ + cmType = ICM; + IndexColorModel icm = (IndexColorModel) cm; + colorMapSize = icm.getMapSize(); + colorMap = new int[colorMapSize]; + icm.getRGBs(colorMap); + transpPixel = icm.getTransparentPixel(); + isGrayPallete = Surface.isGrayPallete(icm); + + if(sm instanceof MultiPixelPackedSampleModel){ + smType = MPPSM; + MultiPixelPackedSampleModel mppsm = + (MultiPixelPackedSampleModel) sm; + scanlineStride = mppsm.getScanlineStride(); + }else if(sm instanceof ComponentSampleModel){ + smType = CSM; + ComponentSampleModel csm = + (ComponentSampleModel) sm; + scanlineStride = csm.getScanlineStride(); + }else{ + // awt.4D=The raster is incompatible with this ColorModel + throw new IllegalArgumentException(Messages.getString("awt.4D")); //$NON-NLS-1$ + } + + }else if(cm instanceof ComponentColorModel){ + cmType = CCM; + if(sm instanceof ComponentSampleModel){ + ComponentSampleModel csm = (ComponentSampleModel) sm; + scanlineStride = csm.getScanlineStride(); + bankIndeces = csm.getBankIndices(); + bandOffsets = csm.getBandOffsets(); + if(sm instanceof PixelInterleavedSampleModel){ + smType = PISM; + }else if(sm instanceof BandedSampleModel){ + smType = BSM; + }else{ + smType = CSM; + } + }else{ + // awt.4D=The raster is incompatible with this ColorModel + throw new IllegalArgumentException(Messages.getString("awt.4D")); //$NON-NLS-1$ + } + + }else{ + surfaceDataPtr = 0L; + return; + } + surfaceDataPtr = createSurfStruct(surfaceType, width, height, cmType, csType, smType, dataType, + numComponents, pixelStride, scanlineStride, bits, masks, colorMapSize, + colorMap, transpPixel, isGrayPallete, bankIndeces, bandOffsets, + offset, hasAlpha, isAlphaPre, transparency); + } + + @Override + public void dispose() { + if(surfaceDataPtr != 0L){ + dispose(surfaceDataPtr); + surfaceDataPtr = 0L; + } + } + + public long getCachedData(boolean alphaPre){ + if(nativeDrawable){ + if(cachedDataPtr == 0L || needToRefresh || this.alphaPre != alphaPre){ + cachedDataPtr = updateCache(getSurfaceDataPtr(), data, alphaPre); + this.alphaPre = alphaPre; + validate(); + } + } + return cachedDataPtr; + } + + private native long createSurfStruct(int surfaceType, int width, int height, + int cmType, int csType, int smType, int dataType, + int numComponents, int pixelStride, int scanlineStride, + int bits[], int masks[], int colorMapSize, int colorMap[], + int transpPixel, boolean isGrayPalette, int bankIndeces[], + int bandOffsets[], int offset, boolean hasAlpha, boolean isAlphaPre, + int transparency); + + private native void dispose(long structPtr); + + private native void setImageSize(long structPtr, int width, int height); + + private native long updateCache(long structPtr, Object data, boolean alphaPre); + + /** + * Supposes that new raster is compatible with an old one + * @param r + */ + public void setRaster(WritableRaster r) { + raster = r; + data = AwtImageBackdoorAccessor.getInstance().getData(r.getDataBuffer()); + if (surfaceDataPtr != 0) { + setImageSize(surfaceDataPtr, r.getWidth(), r.getHeight()); + } + this.width = r.getWidth(); + this.height = r.getHeight(); + } + + @Override + public long lock() { + // TODO + return 0; + } + + @Override + public void unlock() { + //TODO + } + + @Override + public Surface getImageSurface() { + return this; + } + + public void dataChanged() { + needToRefresh = true; + clearValidCaches(); + } + + public void dataTaken() { + dataTaken = true; + needToRefresh = true; + clearValidCaches(); + } + + public void dataReleased(){ + dataTaken = false; + needToRefresh = true; + clearValidCaches(); + } + + @Override + public void invalidate(){ + needToRefresh = true; + clearValidCaches(); + } + + @Override + public void validate(){ + if(!needToRefresh) { + return; + } + if(!dataTaken){ + needToRefresh = false; + AwtImageBackdoorAccessor ba = AwtImageBackdoorAccessor.getInstance(); + ba.validate(raster.getDataBuffer()); + } + + } + + @Override + public boolean invalidated(){ + return needToRefresh; + } +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/MultiRectArea.java b/app/src/main/java/org/apache/harmony/awt/gl/MultiRectArea.java new file mode 100644 index 000000000..bb1557d3f --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/MultiRectArea.java @@ -0,0 +1,836 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Denis M. Kishenko + * @version $Revision$ + */ +package org.apache.harmony.awt.gl; + +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.PathIterator; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.util.ArrayList; +import java.util.NoSuchElementException; + +import org.apache.harmony.awt.internal.nls.Messages; + +public class MultiRectArea implements Shape { + + /** + * If CHECK is true validation check active + */ + private static final boolean CHECK = false; + + boolean sorted = true; + + /** + * Rectangle buffer + */ + public int[] rect; + + /** + * Bounding box + */ + Rectangle bounds; + + /** + * Result rectangle array + */ + Rectangle[] rectangles; + + /** + * LineCash provides creating MultiRectArea line by line. Used in JavaShapeRasterizer. + */ + public static class LineCash extends MultiRectArea { + + int lineY; + int bottomCount; + int[] bottom; + + public LineCash(int size) { + super(); + bottom = new int[size]; + bottomCount = 0; + } + + public void setLine(int y) { + lineY = y; + } + + public void skipLine() { + lineY++; + bottomCount = 0; + } + + public void addLine(int[] points, int pointCount) { + int bottomIndex = 0; + int pointIndex = 0; + int rectIndex = 0; + int pointX1 = 0; + int pointX2 = 0; + int bottomX1 = 0; + int bottomX2 = 0; + boolean appendRect = false; + boolean deleteRect = false; + int lastCount = bottomCount; + + while (bottomIndex < lastCount || pointIndex < pointCount) { + + appendRect = false; + deleteRect = false; + + if (bottomIndex < lastCount) { + rectIndex = bottom[bottomIndex]; + bottomX1 = rect[rectIndex]; + bottomX2 = rect[rectIndex + 2]; + } else { + appendRect = true; + } + + if (pointIndex < pointCount) { + pointX1 = points[pointIndex]; + pointX2 = points[pointIndex + 1]; + } else { + deleteRect = true; + } + + if (!deleteRect && !appendRect) { + if (pointX1 == bottomX1 && pointX2 == bottomX2) { + rect[rectIndex + 3] = rect[rectIndex + 3] + 1; + pointIndex += 2; + bottomIndex++; + continue; + } + deleteRect = pointX2 >= bottomX1; + appendRect = pointX1 <= bottomX2; + } + + if (deleteRect) { + if (bottomIndex < bottomCount - 1) { + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(bottom, bottomIndex + 1, bottom, bottomIndex, bottomCount - bottomIndex - 1); + rectIndex -= 4; + } + bottomCount--; + lastCount--; + } + + if (appendRect) { + int i = rect[0]; + bottom[bottomCount++] = i; + rect = MultiRectAreaOp.checkBufSize(rect, 4); + rect[i++] = pointX1; + rect[i++] = lineY; + rect[i++] = pointX2; + rect[i++] = lineY; + pointIndex += 2; + } + } + lineY++; + + invalidate(); + } + + } + + /** + * RectCash provides simple creating MultiRectArea + */ + public static class RectCash extends MultiRectArea { + + int[] cash; + + public RectCash() { + super(); + cash = new int[MultiRectAreaOp.RECT_CAPACITY]; + cash[0] = 1; + } + + public void addRectCashed(int x1, int y1, int x2, int y2) { + addRect(x1, y1, x2, y2); + invalidate(); +/* + // Exclude from cash unnecessary rectangles + int i = 1; + while(i < cash[0]) { + if (rect[cash[i] + 3] >= y1 - 1) { + if (i > 1) { + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(cash, i, cash, 1, cash[0] - i); + } + break; + } + i++; + } + cash[0] -= i - 1; + + // Find in cash rectangle to concatinate + i = 1; + while(i < cash[0]) { + int index = cash[i]; + if (rect[index + 3] != y1 - 1) { + break; + } + if (rect[index] == x1 && rect[index + 2] == x2) { + rect[index + 3] += y2 - y1 + 1; + + int pos = i + 1; + while(pos < cash[0]) { + if (rect[index + 3] <= rect[cash[i] + 3]) { + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(cash, i + 1, cash, i, pos - i); + break; + } + i++; + } + cash[pos - 1] = index; + + invalidate(); + return; + } + i++; + } + + // Add rectangle to buffer + int index = rect[0]; + rect = MultiRectAreaOp.checkBufSize(rect, 4); + rect[index + 0] = x1; + rect[index + 1] = y1; + rect[index + 2] = x2; + rect[index + 3] = y2; + + // Add rectangle to cash + int length = cash[0]; + cash = MultiRectAreaOp.checkBufSize(cash, 1); + while(i < length) { + if (y2 <= rect[cash[i] + 3]) { + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(cash, i, cash, i + 1, length - i); + break; + } + i++; + } + cash[i] = index; + invalidate(); +*/ + } + + public void addRectCashed(int[] rect, int rectOff, int rectLength) { + for(int i = rectOff; i < rectOff + rectLength;) { + addRect(rect[i++], rect[i++], rect[i++], rect[i++]); +// addRectCashed(rect[i++], rect[i++], rect[i++], rect[i++]); + } + } + + } + + /** + * MultiRectArea path iterator + */ + class Iterator implements PathIterator { + + int type; + int index; + int pos; + + int[] rect; + AffineTransform t; + + Iterator(MultiRectArea mra, AffineTransform t) { + rect = new int[mra.rect[0] - 1]; + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(mra.rect, 1, rect, 0, rect.length); + this.t = t; + } + + public int getWindingRule() { + return WIND_NON_ZERO; + } + + public boolean isDone() { + return pos >= rect.length; + } + + public void next() { + if (index == 4) { + pos += 4; + } + index = (index + 1) % 5; + } + + public int currentSegment(double[] coords) { + if (isDone()) { + // awt.4B=Iiterator out of bounds + throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$ + } + int type = 0; + + switch(index) { + case 0 : + type = SEG_MOVETO; + coords[0] = rect[pos + 0]; + coords[1] = rect[pos + 1]; + break; + case 1: + type = SEG_LINETO; + coords[0] = rect[pos + 2]; + coords[1] = rect[pos + 1]; + break; + case 2: + type = SEG_LINETO; + coords[0] = rect[pos + 2]; + coords[1] = rect[pos + 3]; + break; + case 3: + type = SEG_LINETO; + coords[0] = rect[pos + 0]; + coords[1] = rect[pos + 3]; + break; + case 4: + type = SEG_CLOSE; + break; + } + + if (t != null) { + t.transform(coords, 0, coords, 0, 1); + } + return type; + } + + public int currentSegment(float[] coords) { + if (isDone()) { + // awt.4B=Iiterator out of bounds + throw new NoSuchElementException(Messages.getString("awt.4B")); //$NON-NLS-1$ + } + int type = 0; + + switch(index) { + case 0 : + type = SEG_MOVETO; + coords[0] = rect[pos + 0]; + coords[1] = rect[pos + 1]; + break; + case 1: + type = SEG_LINETO; + coords[0] = rect[pos + 2]; + coords[1] = rect[pos + 1]; + break; + case 2: + type = SEG_LINETO; + coords[0] = rect[pos + 2]; + coords[1] = rect[pos + 3]; + break; + case 3: + type = SEG_LINETO; + coords[0] = rect[pos + 0]; + coords[1] = rect[pos + 3]; + break; + case 4: + type = SEG_CLOSE; + break; + } + + if (t != null) { + t.transform(coords, 0, coords, 0, 1); + } + return type; + } + + } + + /** + * Constructs a new empty MultiRectArea + */ + public MultiRectArea() { + rect = MultiRectAreaOp.createBuf(0); + } + + public MultiRectArea(boolean sorted) { + this(); + this.sorted = sorted; + } + + /** + * Constructs a new MultiRectArea as a copy of another one + */ + public MultiRectArea(MultiRectArea mra) { + if (mra == null) { + rect = MultiRectAreaOp.createBuf(0); + } else { + rect = new int[mra.rect.length]; + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(mra.rect, 0, rect, 0, mra.rect.length); + check(this, "MultiRectArea(MRA)"); //$NON-NLS-1$ + } + } + + /** + * Constructs a new MultiRectArea consists of single rectangle + */ + public MultiRectArea(Rectangle r) { + rect = MultiRectAreaOp.createBuf(0); + if (r != null && !r.isEmpty()) { + rect[0] = 5; + rect[1] = r.x; + rect[2] = r.y; + rect[3] = r.x + r.width - 1; + rect[4] = r.y + r.height - 1; + } + check(this, "MultiRectArea(Rectangle)"); //$NON-NLS-1$ + } + + /** + * Constructs a new MultiRectArea consists of single rectangle + */ + public MultiRectArea(int x0, int y0, int x1, int y1) { + rect = MultiRectAreaOp.createBuf(0); + if (x1 >= x0 && y1 >= y0) { + rect[0] = 5; + rect[1] = x0; + rect[2] = y0; + rect[3] = x1; + rect[4] = y1; + } + check(this, "MultiRectArea(Rectangle)"); //$NON-NLS-1$ + } + + /** + * Constructs a new MultiRectArea and append rectangle from buffer + */ + public MultiRectArea(Rectangle[] buf) { + this(); + for (Rectangle element : buf) { + add(element); + } + } + + /** + * Constructs a new MultiRectArea and append rectangle from array + */ + public MultiRectArea(ArrayList buf) { + this(); + for(int i = 0; i < buf.size(); i++) { + add(buf.get(i)); + } + } + + /** + * Sort rectangle buffer + */ + void resort() { + int[] buf = new int[4]; + for(int i = 1; i < rect[0]; i += 4) { + int k = i; + int x1 = rect[k]; + int y1 = rect[k + 1]; + for(int j = i + 4; j < rect[0]; j += 4) { + int x2 = rect[j]; + int y2 = rect[j + 1]; + if (y1 > y2 || (y1 == y2 && x1 > x2)) { + x1 = x2; + y1 = y2; + k = j; + } + } + if (k != i) { + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(rect, i, buf, 0, 4); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(rect, k, rect, i, 4); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(buf, 0, rect, k, 4); + } + } + invalidate(); + } + + /** + * Tests equals with another object + */ + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof MultiRectArea) { + MultiRectArea mra = (MultiRectArea) obj; + for(int i = 0; i < rect[0]; i++) { + if (rect[i] != mra.rect[i]) { + return false; + } + } + return true; + } + return false; + } + + /** + * Checks validation of MultiRectArea object + */ + static MultiRectArea check(MultiRectArea mra, String msg) { + if (CHECK && mra != null) { + if (MultiRectArea.checkValidation(mra.getRectangles(), mra.sorted) != -1) { + // awt.4C=Invalid MultiRectArea in method {0} + new RuntimeException(Messages.getString("awt.4C", msg)); //$NON-NLS-1$ + } + } + return mra; + } + + /** + * Checks validation of MultiRectArea object + */ + public static int checkValidation(Rectangle[] r, boolean sorted) { + + // Check width and height + for(int i = 0; i < r.length; i++) { + if (r[i].width <= 0 || r[i].height <= 0) { + return i; + } + } + + // Check order + if (sorted) { + for(int i = 1; i < r.length; i++) { + if (r[i - 1].y > r[i].y) { + return i; + } + if (r[i - 1].y == r[i].y) { + if (r[i - 1].x > r[i].x) { + return i; + } + } + } + } + + // Check override + for(int i = 0; i < r.length; i++) { + for(int j = i + 1; j < r.length; j++) { + if (r[i].intersects(r[j])) { + return i; + } + } + } + + return -1; + } + + /** + * Assigns rectangle from another buffer + */ + protected void setRect(int[] buf, boolean copy) { + if (copy) { + rect = new int[buf.length]; + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(buf, 0, rect, 0, buf.length); + } else { + rect = buf; + } + invalidate(); + } + + /** + * Union with another MultiRectArea object + */ + public void add(MultiRectArea mra) { + setRect(union(this, mra).rect, false); + invalidate(); + } + + /** + * Intersect with another MultiRectArea object + */ + public void intersect(MultiRectArea mra) { + setRect(intersect(this, mra).rect, false); + invalidate(); + } + + /** + * Subtract another MultiRectArea object + */ + public void substract(MultiRectArea mra) { + setRect(subtract(this, mra).rect, false); + invalidate(); + } + + /** + * Union with Rectangle object + */ + public void add(Rectangle rect) { + setRect(union(this, new MultiRectArea(rect)).rect, false); + invalidate(); + } + + /** + * Intersect with Rectangle object + */ + public void intersect(Rectangle rect) { + setRect(intersect(this, new MultiRectArea(rect)).rect, false); + invalidate(); + } + + /** + * Subtract rectangle object + */ + public void substract(Rectangle rect) { + setRect(subtract(this, new MultiRectArea(rect)).rect, false); + } + + /** + * Union two MutliRectareArea objects + */ + public static MultiRectArea intersect(MultiRectArea src1, MultiRectArea src2) { + MultiRectArea res = check(MultiRectAreaOp.Intersection.getResult(src1, src2), "intersect(MRA,MRA)"); //$NON-NLS-1$ + return res; + } + + /** + * Intersect two MultiRectArea objects + */ + public static MultiRectArea union(MultiRectArea src1, MultiRectArea src2) { + MultiRectArea res = check(new MultiRectAreaOp.Union().getResult(src1, src2), "union(MRA,MRA)"); //$NON-NLS-1$ + return res; + } + + /** + * Subtract two MultiRectArea objects + */ + public static MultiRectArea subtract(MultiRectArea src1, MultiRectArea src2) { + MultiRectArea res = check(MultiRectAreaOp.Subtraction.getResult(src1, src2), "subtract(MRA,MRA)"); //$NON-NLS-1$ + return res; + } + + /** + * Print MultiRectArea object to output stream + */ + public static void print(MultiRectArea mra, String msg) { + if (mra == null) { + System.out.println(msg + "=null"); //$NON-NLS-1$ + } else { + Rectangle[] rects = mra.getRectangles(); + System.out.println(msg + "(" + rects.length + ")"); //$NON-NLS-1$ //$NON-NLS-2$ + for (Rectangle element : rects) { + System.out.println( + element.x + "," + //$NON-NLS-1$ + element.y + "," + //$NON-NLS-1$ + (element.x + element.width - 1) + "," + //$NON-NLS-1$ + (element.y + element.height - 1)); + } + } + } + + /** + * Translate MultiRectArea object by (x, y) + */ + public void translate(int x, int y) { + for(int i = 1; i < rect[0];) { + rect[i++] += x; + rect[i++] += y; + rect[i++] += x; + rect[i++] += y; + } + + if (bounds != null && !bounds.isEmpty()) { + bounds.translate(x, y); + } + + if (rectangles != null) { + for (Rectangle element : rectangles) { + element.translate(x, y); + } + } + } + + /** + * Add rectangle to the buffer without any checking + */ + public void addRect(int x1, int y1, int x2, int y2) { + int i = rect[0]; + rect = MultiRectAreaOp.checkBufSize(rect, 4); + rect[i++] = x1; + rect[i++] = y1; + rect[i++] = x2; + rect[i++] = y2; + } + + /** + * Tests is MultiRectArea empty + */ + public boolean isEmpty() { + return rect[0] == 1; + } + + void invalidate() { + bounds = null; + rectangles = null; + } + + /** + * Returns bounds of MultiRectArea object + */ + public Rectangle getBounds() { + if (bounds != null) { + return bounds; + } + + if (isEmpty()) { + return bounds = new Rectangle(); + } + + int x1 = rect[1]; + int y1 = rect[2]; + int x2 = rect[3]; + int y2 = rect[4]; + + for(int i = 5; i < rect[0]; i += 4) { + int rx1 = rect[i + 0]; + int ry1 = rect[i + 1]; + int rx2 = rect[i + 2]; + int ry2 = rect[i + 3]; + if (rx1 < x1) { + x1 = rx1; + } + if (rx2 > x2) { + x2 = rx2; + } + if (ry1 < y1) { + y1 = ry1; + } + if (ry2 > y2) { + y2 = ry2; + } + } + + return bounds = new Rectangle(x1, y1, x2 - x1 + 1, y2 - y1 + 1); + } + + /** + * Recturn rectangle count in the buffer + */ + public int getRectCount() { + return (rect[0] - 1) / 4; + } + + /** + * Returns Rectangle array + */ + public Rectangle[] getRectangles() { + if (rectangles != null) { + return rectangles; + } + + rectangles = new Rectangle[(rect[0] - 1) / 4]; + int j = 0; + for(int i = 1; i < rect[0]; i += 4) { + rectangles[j++] = new Rectangle( + rect[i], + rect[i + 1], + rect[i + 2] - rect[i] + 1, + rect[i + 3] - rect[i + 1] + 1); + } + return rectangles; + } + + /** + * Returns Bounds2D + */ + public Rectangle2D getBounds2D() { + return getBounds(); + } + + /** + * Tests does point lie inside MultiRectArea object + */ + public boolean contains(double x, double y) { + for(int i = 1; i < rect[0]; i+= 4) { + if (rect[i] <= x && x <= rect[i + 2] && rect[i + 1] <= y && y <= rect[i + 3]) { + return true; + } + } + return false; + } + + /** + * Tests does Point2D lie inside MultiRectArea object + */ + public boolean contains(Point2D p) { + return contains(p.getX(), p.getY()); + } + + /** + * Tests does rectangle lie inside MultiRectArea object + */ + public boolean contains(double x, double y, double w, double h) { + throw new RuntimeException("Not implemented"); //$NON-NLS-1$ + } + + /** + * Tests does Rectangle2D lie inside MultiRectArea object + */ + public boolean contains(Rectangle2D r) { + throw new RuntimeException("Not implemented"); //$NON-NLS-1$ + } + + /** + * Tests does rectangle intersect MultiRectArea object + */ + public boolean intersects(double x, double y, double w, double h) { + Rectangle r = new Rectangle(); + r.setRect(x, y, w, h); + return intersects(r); + } + + /** + * Tests does Rectangle2D intersect MultiRectArea object + */ + public boolean intersects(Rectangle2D r) { + if (r == null || r.isEmpty()) { + return false; + } + for(int i = 1; i < rect[0]; i+= 4) { + if (r.intersects(rect[i], rect[i+1], rect[i + 2]-rect[i]+1, rect[i + 3]-rect[i + 1]+1)) { + return true; + } + } + return false; + } + + /** + * Returns path iterator + */ + public PathIterator getPathIterator(AffineTransform t, double flatness) { + return new Iterator(this, t); + } + + /** + * Returns path iterator + */ + public PathIterator getPathIterator(AffineTransform t) { + return new Iterator(this, t); + } + + /** + * Returns MultiRectArea object converted to string + */ + @Override + public String toString() { + int cnt = getRectCount(); + StringBuffer sb = new StringBuffer((cnt << 5) + 128); + sb.append(getClass().getName()).append(" ["); //$NON-NLS-1$ + for(int i = 1; i < rect[0]; i += 4) { + sb.append(i > 1 ? ", [" : "[").append(rect[i]).append(", ").append(rect[i + 1]). //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + append(", ").append(rect[i + 2] - rect[i] + 1).append(", "). //$NON-NLS-1$ //$NON-NLS-2$ + append(rect[i + 3] - rect[i + 1] + 1).append("]"); //$NON-NLS-1$ + } + return sb.append("]").toString(); //$NON-NLS-1$ + } + +} + diff --git a/app/src/main/java/org/apache/harmony/awt/gl/MultiRectAreaOp.java b/app/src/main/java/org/apache/harmony/awt/gl/MultiRectAreaOp.java new file mode 100644 index 000000000..bd378ed79 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/MultiRectAreaOp.java @@ -0,0 +1,837 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Denis M. Kishenko + * @version $Revision$ + */ +package org.apache.harmony.awt.gl; + +import java.awt.Rectangle; + +public class MultiRectAreaOp { + + /** + * Rectangle buffer capacity + */ + public static final int RECT_CAPACITY = 16; + + /** + * If number of rectangle in MultiRectArea object less than MAX_SIMPLE simple algorithm applies + */ + private static final int MAX_SIMPLE = 8; + + /** + * Create buffer + */ + public static int[] createBuf(int capacity) { + if (capacity == 0) { + capacity = RECT_CAPACITY; + } + int[] buf = new int[capacity]; + buf[0] = 1; + return buf; + } + + /** + * Checks buffer size and reallocate if necessary + */ + public static int[] checkBufSize(int[] buf, int capacity) { + if (buf[0] + capacity >= buf.length) { + int length = buf[0] + (capacity > RECT_CAPACITY ? capacity : RECT_CAPACITY); + int[] tmp = new int[length]; + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(buf, 0, tmp, 0, buf[0]); + buf = tmp; + } + buf[0] += capacity; + return buf; + } + + /** + * Region class provides basic functionlity for MultiRectArea objects to make logical operations + */ + static class Region { + + int[] region; + int[] active; + int[] bottom; + int index; + + public Region(int[] region) { + this.region = region; + active = new int[RECT_CAPACITY]; + bottom = new int[RECT_CAPACITY]; + active[0] = 1; + bottom[0] = 1; + index = 1; + } + + void addActive(int index) { + int length = active[0]; + active = checkBufSize(active, 4); + int i = 1; + + while(i < length) { + if (region[index] < active[i]) { + // Insert + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(active, i, active, i + 4, length - i); + length = i; + break; + } + i += 4; + } + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(region, index, active, length, 4); + + } + + void findActive(int top, int bottom) { + while(index < region[0]) { + if (region[index + 1] > bottom) { // y1 > bottom + return; + } + if (region[index + 3] >= top) { // y2 >= top + addActive(index); + } + index += 4; + } + } + + void deleteActive(int bottom) { + int length = active[0]; + for(int i = 1; i < length;) { + if (active[i + 3] == bottom) { + length -= 4; + if (i < length) { + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(active, i + 4, active, i, length - i); + } + } else { + i += 4; + } + } + active[0] = length; + } + + void deleteActive() { + int length = active[0]; + for(int i = length - 4; i > 0; i -= 4) { + if (active[i + 1] > active[i + 3]) { + length -= 4; + if (i < length) { + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(active, i + 4, active, i, length - i); + } + } + } + active[0] = length; + } + + void createLevel(int[] level) { + int levelCount = 1; + int topIndex = 1; + int i = 1; + while(i < region[0]) { + + int top = region[i + 1]; + int bottom = region[i + 3] + 1; + int j = topIndex; + + addTop: { + while(j < levelCount) { + if (level[j] == top) { + break addTop; + } + if (level[j] > top) { + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(level, j, level, j + 1, levelCount - j); + break; + } + j++; + } + + level[j] = top; + levelCount++; + topIndex = j; + } + + addBottom: { + while(j < levelCount) { + if (level[j] == bottom) { + break addBottom; + } + if (level[j] > bottom) { + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(level, j, level, j + 1, levelCount - j); + break; + } + j++; + }; + + level[j] = bottom; + levelCount++; + } + + i += 4; + } + level[0] = levelCount; + } + + static void sortOrdered(int[] src1, int[] src2, int[] dst) { + int length1 = src1[0]; + int length2 = src2[0]; + int count = 1; + int i1 = 1; + int i2 = 1; + int v1 = src1[1]; + int v2 = src2[1]; + while(true) { + + LEFT: { + while(i1 < length1) { + v1 = src1[i1]; + if (v1 >= v2) { + break LEFT; + } + dst[count++] = v1; + i1++; + } + while(i2 < length2) { + dst[count++] = src2[i2++]; + } + dst[0] = count; + return; + } + + RIGHT: { + while(i2 < length2) { + v2 = src2[i2]; + if (v2 >= v1) { + break RIGHT; + } + dst[count++] = v2; + i2++; + } + while(i1 < length1) { + dst[count++] = src1[i1++]; + } + dst[0] = count; + return; + } + + if (v1 == v2) { + dst[count++] = v1; + i1++; + i2++; + if (i1 < length1) { + v1 = src1[i1]; + } + if (i2 < length2 - 1) { + v2 = src2[i2]; + } + } + } + // UNREACHABLE + } + + } + + /** + * Intersection class provides intersection of two MultiRectAre aobjects + */ + static class Intersection { + + static void intersectRegions(int[] reg1, int[] reg2, MultiRectArea.RectCash dst, int height1, int height2) { + + Region d1 = new Region(reg1); + Region d2 = new Region(reg2); + + int[] level = new int[height1 + height2]; + int[] level1 = new int[height1]; + int[] level2 = new int[height2]; + d1.createLevel(level1); + d2.createLevel(level2); + Region.sortOrdered(level1, level2, level); + + int top; + int bottom = level[1] - 1; + for(int i = 2; i < level[0]; i++) { + + top = bottom + 1; + bottom = level[i] - 1; + + d1.findActive(top, bottom); + d2.findActive(top, bottom); + + int i1 = 1; + int i2 = 1; + + while(i1 < d1.active[0] && i2 < d2.active[0]) { + + int x11 = d1.active[i1]; + int x12 = d1.active[i1 + 2]; + int x21 = d2.active[i2]; + int x22 = d2.active[i2 + 2]; + + if (x11 <= x21) { + if (x12 >= x21) { + if (x12 <= x22) { + dst.addRectCashed(x21, top, x12, bottom); + i1 += 4; + } else { + dst.addRectCashed(x21, top, x22, bottom); + i2 += 4; + } + } else { + i1 += 4; + } + } else { + if (x22 >= x11) { + if (x22 <= x12) { + dst.addRectCashed(x11, top, x22, bottom); + i2 += 4; + } else { + dst.addRectCashed(x11, top, x12, bottom); + i1 += 4; + } + } else { + i2 += 4; + } + } + } + + d1.deleteActive(bottom); + d2.deleteActive(bottom); + } + } + + static int[] simpleIntersect(MultiRectArea src1, MultiRectArea src2) { + int[] rect1 = src1.rect; + int[] rect2 = src2.rect; + int[] rect = createBuf(0); + + int k = 1; + for(int i = 1; i < rect1[0];) { + + int x11 = rect1[i++]; + int y11 = rect1[i++]; + int x12 = rect1[i++]; + int y12 = rect1[i++]; + + for(int j = 1; j < rect2[0];) { + + int x21 = rect2[j++]; + int y21 = rect2[j++]; + int x22 = rect2[j++]; + int y22 = rect2[j++]; + + if (x11 <= x22 && x12 >= x21 && + y11 <= y22 && y12 >= y21) + { + rect = checkBufSize(rect, 4); + rect[k++] = x11 > x21 ? x11 : x21; + rect[k++] = y11 > y21 ? y11 : y21; + rect[k++] = x12 > x22 ? x22 : x12; + rect[k++] = y12 > y22 ? y22 : y12; + } + } + } + + rect[0] = k; + return rect; + } + + public static MultiRectArea getResult(MultiRectArea src1, MultiRectArea src2) { + + if (src1 == null || src2 == null || src1.isEmpty() || src2.isEmpty()) { + return new MultiRectArea(); + } + + MultiRectArea.RectCash dst = new MultiRectArea.RectCash(); + + if (!src1.sorted || !src2.sorted || + src1.getRectCount() <= MAX_SIMPLE || src2.getRectCount() <= MAX_SIMPLE) + { + dst.setRect(simpleIntersect(src1, src2), false); + } else { + Rectangle bounds1 = src1.getBounds(); + Rectangle bounds2 = src2.getBounds(); + Rectangle bounds3 = bounds1.intersection(bounds2); + if (bounds3.width > 0 && bounds3.height > 0) { + intersectRegions(src1.rect, src2.rect, dst, bounds1.height + 2, bounds2.height + 2); + } + } + + return dst; + } + + } + + /** + * Union class provides union of two MultiRectAre aobjects + */ + static class Union { + + int rx1, rx2; + int top, bottom; + MultiRectArea.RectCash dst; + + boolean next(Region d, int index) { + int x1 = d.active[index]; + int x2 = d.active[index + 2]; + boolean res = false; + + if (x2 < rx1 - 1) { + res = true; + dst.addRectCashed(x1, top, x2, bottom); + } else + if (x1 > rx2 + 1) { + res = false; + dst.addRectCashed(rx1, top, rx2, bottom); + rx1 = x1; + rx2 = x2; + } else { + res = x2 <= rx2; + rx1 = Math.min(x1, rx1); + rx2 = Math.max(x2, rx2); + } + + // Top + if (d.active[index + 1] < top) { + dst.addRectCashed(x1, d.active[index + 1], x2, top - 1); + } + // Bottom + if (d.active[index + 3] > bottom) { + d.active[index + 1] = bottom + 1; + } + return res; + } + + void check(Region d, int index, boolean t) { + int x1 = d.active[index]; + int x2 = d.active[index + 2]; + // Top + if (d.active[index + 1] < top) { + dst.addRectCashed(x1, d.active[index + 1], x2, top - 1); + } + if (t) { + dst.addRectCashed(x1, top, x2, bottom); + } + // Bottom + if (d.active[index + 3] > bottom) { + d.active[index + 1] = bottom + 1; + } + } + + void unionRegions(int[] reg1, int[] reg2, int height1, int height2) { + Region d1 = new Region(reg1); + Region d2 = new Region(reg2); + + int[] level = new int[height1 + height2]; + int[] level1 = new int[height1]; + int[] level2 = new int[height2]; + d1.createLevel(level1); + d2.createLevel(level2); + Region.sortOrdered(level1, level2, level); + + bottom = level[1] - 1; + for(int i = 2; i < level[0]; i++) { + + top = bottom + 1; + bottom = level[i] - 1; + + d1.findActive(top, bottom); + d2.findActive(top, bottom); + + int i1 = 1; + int i2 = 1; + boolean res1, res2; + + if (d1.active[0] > 1) { + check(d1, 1, false); + rx1 = d1.active[1]; + rx2 = d1.active[3]; + i1 += 4; + res1 = false; + res2 = true; + } else + if (d2.active[0] > 1) { + check(d2, 1, false); + rx1 = d2.active[1]; + rx2 = d2.active[3]; + i2 += 4; + res1 = true; + res2 = false; + } else { + continue; + } + + outer: + while(true) { + + while (res1) { + if (i1 >= d1.active[0]) { + dst.addRectCashed(rx1, top, rx2, bottom); + while(i2 < d2.active[0]) { + check(d2, i2, true); + i2 += 4; + } + break outer; + } + res1 = next(d1, i1); + i1 += 4; + } + + while (res2) { + if (i2 >= d2.active[0]) { + dst.addRectCashed(rx1, top, rx2, bottom); + while(i1 < d1.active[0]) { + check(d1, i1, true); + i1 += 4; + } + break outer; + } + res2 = next(d2, i2); + i2 += 4; + } + + res1 = true; + res2 = true; + } // while + + d1.deleteActive(bottom); + d2.deleteActive(bottom); + + } + } + + static void simpleUnion(MultiRectArea src1, MultiRectArea src2, MultiRectArea dst) { + if (src1.getRectCount() < src2.getRectCount()) { + simpleUnion(src2, src1, dst); + } else { + Subtraction.simpleSubtract(src1, src2, dst); + int pos = dst.rect[0]; + int size = src2.rect[0] - 1; + dst.rect = checkBufSize(dst.rect, size); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(src2.rect,1, dst.rect, pos, size); + dst.resort(); + } + } + + MultiRectArea getResult(MultiRectArea src1, MultiRectArea src2) { + + if (src1 == null || src1.isEmpty()) { + return new MultiRectArea(src2); + } + + if (src2 == null || src2.isEmpty()) { + return new MultiRectArea(src1); + } + + dst = new MultiRectArea.RectCash(); + + if (!src1.sorted || !src2.sorted || + src1.getRectCount() <= MAX_SIMPLE || src2.getRectCount() <= MAX_SIMPLE) + { + simpleUnion(src1, src2, dst); + } else { + Rectangle bounds1 = src1.getBounds(); + Rectangle bounds2 = src2.getBounds(); + Rectangle bounds3 = bounds1.intersection(bounds2); + + if (bounds3.width < 0 || bounds3.height < 0) { + if (bounds1.y + bounds1.height < bounds2.y) { + dst.setRect(addVerRegion(src1.rect, src2.rect), false); + } else + if (bounds2.y + bounds2.height < bounds1.y) { + dst.setRect(addVerRegion(src2.rect, src1.rect), false); + } else + if (bounds1.x < bounds2.x) { + dst.setRect(addHorRegion(src1.rect, src2.rect), false); + } else { + dst.setRect(addHorRegion(src2.rect, src1.rect), false); + } + } else { + unionRegions(src1.rect, src2.rect, bounds1.height + 2, bounds2.height + 2); + } + } + + return dst; + } + + int[] addVerRegion(int[] top, int[] bottom) { + int length = top[0] + bottom[0] - 1; + int[] dst = new int[length]; + dst[0] = length; + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(top, 1, dst, 1, top[0] - 1); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(bottom, 1, dst, top[0], bottom[0] - 1); + return dst; + } + + int[] addHorRegion(int[] left, int[] right) { + int count1 = left[0]; + int count2 = right[0]; + int[] dst = new int[count1 + count2 + 1]; + int count = 1; + int index1 = 1; + int index2 = 1; + + int top1 = left[2]; + int top2 = right[2]; + int pos1, pos2; + + while(true) { + + if (index1 >= count1) { + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(right, index2, dst, count, count2 - index2); + count += count2 - index2; + break; + } + if (index2 >= count2) { + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(left, index1, dst, count, count1 - index1); + count += count1 - index1; + break; + } + + if (top1 < top2) { + pos1 = index1; + do { + index1 += 4; + } while (index1 < count1 && (top1 = left[index1 + 1]) < top2); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(left, pos1, dst, count, index1 - pos1); + count += index1 - pos1; + continue; + } + + if (top1 > top2) { + pos2 = index2; + do { + index2 += 4; + } while (index2 < count2 && (top2 = right[index2 + 1]) < top1); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(right, pos2, dst, count, index2 - pos2); + count += index2 - pos2; + continue; + } + + int top = top1; + pos1 = index1; + pos2 = index2; + do { + index1 += 4; + } while(index1 < count1 && (top1 = left[index1 + 1]) == top); + do { + index2 += 4; + } while(index2 < count2 && (top2 = right[index2 + 1]) == top); + + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(left, pos1, dst, count, index1 - pos1); + count += index1 - pos1; + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(right, pos2, dst, count, index2 - pos2); + count += index2 - pos2; + } + + dst[0] = count; + return dst; + } + + } + + /** + * Subtraction class provides subtraction of two MultiRectAre aobjects + */ + static class Subtraction { + + static void subtractRegions(int[] reg1, int[] reg2, MultiRectArea.RectCash dst, int height1, int height2) { + Region d1 = new Region(reg1); + Region d2 = new Region(reg2); + + int[] level = new int[height1 + height2]; + int[] level1 = new int[height1]; + int[] level2 = new int[height2]; + d1.createLevel(level1); + d2.createLevel(level2); + Region.sortOrdered(level1, level2, level); + + int top; + int bottom = level[1] - 1; + for(int i = 2; i < level[0]; i++) { + + top = bottom + 1; + bottom = level[i] - 1; + + d1.findActive(top, bottom); + if (d1.active[0] == 1) { + d2.deleteActive(bottom); + continue; + } + + d2.findActive(top, bottom); + + int i1 = 1; + int i2 = 1; + + int rx1 = 0; + int rx2 = 0; + + boolean next = true; + + while(true) { + + if (next) { + next = false; + if (i1 >= d1.active[0]) { + break; + } + // Bottom + d1.active[i1 + 1] = bottom + 1; + rx1 = d1.active[i1]; + rx2 = d1.active[i1 + 2]; + i1 += 4; + } + + if (i2 >= d2.active[0]) { + dst.addRectCashed(rx1, top, rx2, bottom); + for(int j = i1; j < d1.active[0]; j += 4) { + dst.addRectCashed(d1.active[j], top, d1.active[j + 2], bottom); + d1.active[j + 1] = bottom + 1; + } + break; + } + + int x1 = d2.active[i2]; + int x2 = d2.active[i2 + 2]; + + if (rx1 < x1) { + if (rx2 >= x1) { + if (rx2 <= x2) { + // [-----------] + // [-------------] + dst.addRectCashed(rx1, top, x1 - 1, bottom); + next = true; + } else { + // [-----------------] + // [------] + dst.addRectCashed(rx1, top, x1 - 1, bottom); + rx1 = x2 + 1; + i2 += 4; + } + } else { + // [-----] + // [----] + dst.addRectCashed(rx1, top, rx2, bottom); + next = true; + } + } else { + if (rx1 <= x2) { + if (rx2 <= x2) { + // [------] + // [-----------] + next = true; + } else { + // [------------] + // [---------] + rx1 = x2 + 1; + i2 += 4; + } + } else { + // [----] + // [-----] + i2 += 4; + } + } + + } + d1.deleteActive(); + d2.deleteActive(bottom); + } + } + + static void subtractRect(int x11, int y11, int x12, int y12, int[] rect, int index, MultiRectArea dst) { + + for(int i = index; i < rect[0]; i += 4) { + int x21 = rect[i + 0]; + int y21 = rect[i + 1]; + int x22 = rect[i + 2]; + int y22 = rect[i + 3]; + + if (x11 <= x22 && x12 >= x21 && y11 <= y22 && y12 >= y21) { + int top, bottom; + if (y11 < y21) { + subtractRect(x11, y11, x12, y21 - 1, rect, i + 4, dst); + top = y21; + } else { + top = y11; + } + if (y12 > y22) { + subtractRect(x11, y22 + 1, x12, y12, rect, i + 4, dst); + bottom = y22; + } else { + bottom = y12; + } + if (x11 < x21) { + subtractRect(x11, top, x21 - 1, bottom, rect, i + 4, dst); + } + if (x12 > x22) { + subtractRect(x22 + 1, top, x12, bottom, rect, i + 4, dst); + } + return; + } + } + dst.addRect(x11, y11, x12, y12); + } + + static void simpleSubtract(MultiRectArea src1, MultiRectArea src2, MultiRectArea dst) { + for(int i = 1; i < src1.rect[0]; i += 4) { + subtractRect( + src1.rect[i + 0], + src1.rect[i + 1], + src1.rect[i + 2], + src1.rect[i + 3], + src2.rect, + 1, + dst); + } + dst.resort(); + } + + public static MultiRectArea getResult(MultiRectArea src1, MultiRectArea src2) { + + if (src1 == null || src1.isEmpty()) { + return new MultiRectArea(); + } + + if (src2 == null || src2.isEmpty()) { + return new MultiRectArea(src1); + } + + MultiRectArea.RectCash dst = new MultiRectArea.RectCash(); + + if (!src1.sorted || !src2.sorted || + src1.getRectCount() <= MAX_SIMPLE || src2.getRectCount() <= MAX_SIMPLE) + { + simpleSubtract(src1, src2, dst); + } else { + Rectangle bounds1 = src1.getBounds(); + Rectangle bounds2 = src2.getBounds(); + Rectangle bounds3 = bounds1.intersection(bounds2); + + if (bounds3.width > 0 && bounds3.height > 0) { + subtractRegions(src1.rect, src2.rect, dst, bounds1.height + 2, bounds2.height + 2); + } else { + dst.setRect(src1.rect, true); + } + } + + return dst; + } + + } + +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/Surface.java b/app/src/main/java/org/apache/harmony/awt/gl/Surface.java new file mode 100644 index 000000000..8b0ae38b9 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/Surface.java @@ -0,0 +1,309 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + * Created on 10.11.2005 + * + */ +package org.apache.harmony.awt.gl; + +import java.awt.Image; +import java.awt.Transparency; +import java.awt.color.ColorSpace; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.ComponentColorModel; +import java.awt.image.ComponentSampleModel; +import java.awt.image.DataBuffer; +import java.awt.image.DirectColorModel; +import java.awt.image.IndexColorModel; +import java.awt.image.MultiPixelPackedSampleModel; +import java.awt.image.SampleModel; +import java.awt.image.WritableRaster; +import java.util.ArrayList; + +import org.apache.harmony.awt.gl.color.LUTColorConverter; + + +/** + * This class is super class for others types of Surfaces. + * Surface is storing data and data format description, that are using + * in blitting operations + */ +public abstract class Surface implements Transparency{ + + // Color Space Types + public static final int sRGB_CS = 1; + public static final int Linear_RGB_CS = 2; + public static final int Linear_Gray_CS = 3; + public static final int Custom_CS = 0; + + // Color Model Types + public static final int DCM = 1; // Direct Color Model + public static final int ICM = 2; // Index Color Model + public static final int CCM = 3; // Component Color Model + + // Sample Model Types + public static final int SPPSM = 1; // Single Pixel Packed Sample Model + public static final int MPPSM = 2; // Multi Pixel Packed Sample Model + public static final int CSM = 3; // Component Sample Model + public static final int PISM = 4; // Pixel Interleaved Sample Model + public static final int BSM = 5; // Banded Sample Model + + // Surface Types + private static final int ALPHA_MASK = 0xff000000; + private static final int RED_MASK = 0x00ff0000; + private static final int GREEN_MASK = 0x0000ff00; + private static final int BLUE_MASK = 0x000000ff; + private static final int RED_BGR_MASK = 0x000000ff; + private static final int GREEN_BGR_MASK = 0x0000ff00; + private static final int BLUE_BGR_MASK = 0x00ff0000; + private static final int RED_565_MASK = 0xf800; + private static final int GREEN_565_MASK = 0x07e0; + private static final int BLUE_565_MASK = 0x001f; + private static final int RED_555_MASK = 0x7c00; + private static final int GREEN_555_MASK = 0x03e0; + private static final int BLUE_555_MASK = 0x001f; + + static{ + //???AWT + /* + System.loadLibrary("gl"); //$NON-NLS-1$ + initIDs(); + */ + } + + + protected long surfaceDataPtr; // Pointer for Native Surface data + protected int transparency = OPAQUE; + protected int width; + protected int height; + + /** + * This list contains caches with the data of this surface that are valid at the moment. + * Surface should clear this list when its data is updated. + * Caches may check if they are still valid using isCacheValid method. + * When cache gets data from the surface, it should call addValidCache method of the surface. + */ + private final ArrayList validCaches = new ArrayList(); + + public abstract ColorModel getColorModel(); + public abstract WritableRaster getRaster(); + public abstract int getSurfaceType(); // Syrface type. It is equal + // BufferedImge type + /** + * Lock Native Surface data + */ + public abstract long lock(); + + /** + * Unlock Native Surface data + */ + public abstract void unlock(); + + /** + * Dispose Native Surface data + */ + public abstract void dispose(); + public abstract Surface getImageSurface(); + + public long getSurfaceDataPtr(){ + return surfaceDataPtr; + } + + public final boolean isCaheValid(Object cache) { + return validCaches.contains(cache); + } + + public final void addValidCache(Object cache) { + validCaches.add(cache); + } + + protected final void clearValidCaches() { + validCaches.clear(); + } + + /** + * Returns could or coldn't the Surface be blit by Native blitter + * @return - true if the Surface could be blit by Native blitter, + * false in other case + */ + public boolean isNativeDrawable(){ + return true; + } + + public int getTransparency() { + return transparency; + } + + public int getWidth(){ + return width; + } + + public int getHeight(){ + return height; + } + + /** + * If Surface has Raster, this method returns data array of Raster's DataBuffer + * @return - data array + */ + public Object getData(){ + return null; + } + + public boolean invalidated(){ + return true; + } + + public void validate(){} + + public void invalidate(){} + + /** + * Computation type of BufferedImage or Surface + * @param cm - ColorModel + * @param raster - WritableRaste + * @return - type of BufferedImage + */ + public static int getType(ColorModel cm, WritableRaster raster){ + int transferType = cm.getTransferType(); + boolean hasAlpha = cm.hasAlpha(); + ColorSpace cs = cm.getColorSpace(); + int csType = cs.getType(); + SampleModel sm = raster.getSampleModel(); + + if(csType == ColorSpace.TYPE_RGB){ + if(cm instanceof DirectColorModel){ + DirectColorModel dcm = (DirectColorModel) cm; + switch (transferType) { + case DataBuffer.TYPE_INT: + if (dcm.getRedMask() == RED_MASK && + dcm.getGreenMask() == GREEN_MASK && + dcm.getBlueMask() == BLUE_MASK) { + if (!hasAlpha) { + return BufferedImage.TYPE_INT_RGB; + } + if (dcm.getAlphaMask() == ALPHA_MASK) { + if (dcm.isAlphaPremultiplied()) { + return BufferedImage.TYPE_INT_ARGB_PRE; + } + return BufferedImage.TYPE_INT_ARGB; + } + return BufferedImage.TYPE_CUSTOM; + } else if (dcm.getRedMask() == RED_BGR_MASK && + dcm.getGreenMask() == GREEN_BGR_MASK && + dcm.getBlueMask() == BLUE_BGR_MASK) { + if (!hasAlpha) { + return BufferedImage.TYPE_INT_BGR; + } + } else { + return BufferedImage.TYPE_CUSTOM; + } + case DataBuffer.TYPE_USHORT: + if (dcm.getRedMask() == RED_555_MASK && + dcm.getGreenMask() == GREEN_555_MASK && + dcm.getBlueMask() == BLUE_555_MASK && !hasAlpha) { + return BufferedImage.TYPE_USHORT_555_RGB; + } else if (dcm.getRedMask() == RED_565_MASK && + dcm.getGreenMask() == GREEN_565_MASK && + dcm.getBlueMask() == BLUE_565_MASK) { + return BufferedImage.TYPE_USHORT_565_RGB; + } + default: + return BufferedImage.TYPE_CUSTOM; + } + }else if(cm instanceof IndexColorModel){ + IndexColorModel icm = (IndexColorModel) cm; + int pixelBits = icm.getPixelSize(); + if(transferType == DataBuffer.TYPE_BYTE){ + if(sm instanceof MultiPixelPackedSampleModel && !hasAlpha && + pixelBits < 5){ + return BufferedImage.TYPE_BYTE_BINARY; + }else if(pixelBits == 8){ + return BufferedImage.TYPE_BYTE_INDEXED; + } + } + return BufferedImage.TYPE_CUSTOM; + }else if(cm instanceof ComponentColorModel){ + ComponentColorModel ccm = (ComponentColorModel) cm; + if(transferType == DataBuffer.TYPE_BYTE && + sm instanceof ComponentSampleModel){ + ComponentSampleModel csm = + (ComponentSampleModel) sm; + int[] offsets = csm.getBandOffsets(); + int[] bits = ccm.getComponentSize(); + boolean isCustom = false; + for (int i = 0; i < bits.length; i++) { + if (bits[i] != 8 || + offsets[i] != offsets.length - 1 - i) { + isCustom = true; + break; + } + } + if (!isCustom) { + if (!ccm.hasAlpha()) { + return BufferedImage.TYPE_3BYTE_BGR; + } else if (ccm.isAlphaPremultiplied()) { + return BufferedImage.TYPE_4BYTE_ABGR_PRE; + } else { + return BufferedImage.TYPE_4BYTE_ABGR; + } + } + } + return BufferedImage.TYPE_CUSTOM; + } + return BufferedImage.TYPE_CUSTOM; + }else if(cs == LUTColorConverter.LINEAR_GRAY_CS){ + if(cm instanceof ComponentColorModel && + cm.getNumComponents() == 1){ + int bits[] = cm.getComponentSize(); + if(transferType == DataBuffer.TYPE_BYTE && + bits[0] == 8){ + return BufferedImage.TYPE_BYTE_GRAY; + }else if(transferType == DataBuffer.TYPE_USHORT && + bits[0] == 16){ + return BufferedImage.TYPE_USHORT_GRAY; + }else{ + return BufferedImage.TYPE_CUSTOM; + } + } + return BufferedImage.TYPE_CUSTOM; + } + return BufferedImage.TYPE_CUSTOM; + } + + public static Surface getImageSurface(Image image){ + return AwtImageBackdoorAccessor.getInstance().getImageSurface(image); + } + + @Override + protected void finalize() throws Throwable{ + dispose(); + } + + public static boolean isGrayPallete(IndexColorModel icm){ + return AwtImageBackdoorAccessor.getInstance().isGrayPallete(icm); + } + + /** + * Initialization of Native data + * + */ + //???AWT: private static native void initIDs(); +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/TextRenderer.java b/app/src/main/java/org/apache/harmony/awt/gl/TextRenderer.java new file mode 100644 index 000000000..f57952d23 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/TextRenderer.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ +package org.apache.harmony.awt.gl; + +import java.awt.Graphics2D; +import java.awt.font.GlyphVector; + +public abstract class TextRenderer { + + /** + * Draws string on specified Graphics at desired position. + * + * @param g specified Graphics2D object + * @param str String object to draw + * @param x start X position to draw + * @param y start Y position to draw + */ + public abstract void drawString(Graphics2D g, String str, float x, float y); + + /** + * Draws string on specified Graphics at desired position. + * + * @param g specified Graphics2D object + * @param str String object to draw + * @param x start X position to draw + * @param y start Y position to draw + */ + public void drawString(Graphics2D g, String str, int x, int y){ + drawString(g, str, (float)x, (float)y); + } + + /** + * Draws GlyphVector on specified Graphics at desired position. + * + * @param g specified Graphics2D object + * @param glyphVector GlyphVector object to draw + * @param x start X position to draw + * @param y start Y position to draw + */ + public abstract void drawGlyphVector(Graphics2D g, GlyphVector glyphVector, float x, float y); +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/XORComposite.java b/app/src/main/java/org/apache/harmony/awt/gl/XORComposite.java new file mode 100644 index 000000000..e27e1d3f0 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/XORComposite.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + * Created on 21.11.2005 + * + */ +package org.apache.harmony.awt.gl; + +import java.awt.Color; +import java.awt.Composite; +import java.awt.CompositeContext; +import java.awt.RenderingHints; +import java.awt.image.ColorModel; + +public class XORComposite implements Composite { + + Color xorcolor; + + public XORComposite(Color xorcolor){ + this.xorcolor = xorcolor; + } + + public CompositeContext createContext(ColorModel srcCM, ColorModel dstCM, + RenderingHints hints) { + + return new ICompositeContext(this, srcCM, dstCM); + } + + public Color getXORColor(){ + return xorcolor; + } +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/color/ColorConverter.java b/app/src/main/java/org/apache/harmony/awt/gl/color/ColorConverter.java new file mode 100644 index 000000000..c98e11497 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/color/ColorConverter.java @@ -0,0 +1,257 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ +package org.apache.harmony.awt.gl.color; + +import java.awt.color.ColorSpace; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; + +/** + * This class combines ColorScaler, ICC_Transform and NativeImageFormat functionality + * in the workflows for different types of input/output pixel data. + */ +public class ColorConverter { + private ColorScaler scaler = new ColorScaler(); + + public void loadScalingData(ColorSpace cs) { + scaler.loadScalingData(cs); + } + + /** + * Translates pixels, stored in source buffered image and writes the data + * to the destination image. + * @param t - ICC transform + * @param src - source image + * @param dst - destination image + */ + public void translateColor(ICC_Transform t, + BufferedImage src, BufferedImage dst) { + NativeImageFormat srcIF = NativeImageFormat.createNativeImageFormat(src); + NativeImageFormat dstIF = NativeImageFormat.createNativeImageFormat(dst); + + if (srcIF != null && dstIF != null) { + t.translateColors(srcIF, dstIF); + return; + } + + srcIF = createImageFormat(src); + dstIF = createImageFormat(dst); + + short srcChanData[] = (short[]) srcIF.getChannelData(); + short dstChanData[] = (short[]) dstIF.getChannelData(); + + ColorModel srcCM = src.getColorModel(); + int nColorChannels = srcCM.getNumColorComponents(); + scaler.loadScalingData(srcCM.getColorSpace()); // input scaling data + ColorModel dstCM = dst.getColorModel(); + + // Prepare array for alpha channel + float alpha[] = null; + boolean saveAlpha = srcCM.hasAlpha() && dstCM.hasAlpha(); + if (saveAlpha) { + alpha = new float[src.getWidth()*src.getHeight()]; + } + + WritableRaster wr = src.getRaster(); + int srcDataPos = 0, alphaPos = 0; + float normalizedVal[]; + for (int row=0, nRows = srcIF.getNumRows(); row profileHandles = new HashMap(); + + private static boolean isCMMLoaded; + + public static void addHandle(ICC_Profile key, long handle) { + profileHandles.put(key, new Long(handle)); + } + + public static void removeHandle(ICC_Profile key) { + profileHandles.remove(key); + } + + public static long getHandle(ICC_Profile key) { + return profileHandles.get(key).longValue(); + } + + /* ICC profile management */ + public static native long cmmOpenProfile(byte[] data); + public static native void cmmCloseProfile(long profileID); + public static native int cmmGetProfileSize(long profileID); + public static native void cmmGetProfile(long profileID, byte[] data); + public static native int cmmGetProfileElementSize(long profileID, int signature); + public static native void cmmGetProfileElement(long profileID, int signature, + byte[] data); + public static native void cmmSetProfileElement(long profileID, int tagSignature, + byte[] data); + + + /* ICC transforms */ + public static native long cmmCreateMultiprofileTransform( + long[] profileHandles, + int[] renderingIntents + ); + public static native void cmmDeleteTransform(long transformHandle); + public static native void cmmTranslateColors(long transformHandle, + NativeImageFormat src, + NativeImageFormat dest); + + static void loadCMM() { + if (!isCMMLoaded) { + AccessController.doPrivileged( + new PrivilegedAction() { + public Void run() { + System.loadLibrary("lcmm"); //$NON-NLS-1$ + return null; + } + } ); + isCMMLoaded = true; + } + } + + /* load native CMM library */ + static { + loadCMM(); + } +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/color/NativeImageFormat.java b/app/src/main/java/org/apache/harmony/awt/gl/color/NativeImageFormat.java new file mode 100644 index 000000000..9594047cd --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/color/NativeImageFormat.java @@ -0,0 +1,642 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ +package org.apache.harmony.awt.gl.color; + +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.ComponentSampleModel; +import java.awt.image.DataBuffer; +import java.awt.image.Raster; +import java.awt.image.SampleModel; +import java.awt.image.SinglePixelPackedSampleModel; +import java.util.ArrayList; + +import org.apache.harmony.awt.gl.AwtImageBackdoorAccessor; +import org.apache.harmony.awt.internal.nls.Messages; + + +/** + * This class converts java color/sample models to the LCMS pixel formats. + * It also encapsulates all the information about the image format, which native CMM + * needs to have in order to read/write data. + * + * At present planar formats (multiple bands) are not supported + * and they are handled as a common (custom) case. + * Samples other than 1 - 7 bytes and multiple of 8 bits are + * also handled as custom (and won't be supported in the nearest future). + */ +class NativeImageFormat { + ////////////////////////////////////////////// + // LCMS Pixel types + private static final int PT_ANY = 0; // Don't check colorspace + // 1 & 2 are reserved + private static final int PT_GRAY = 3; + private static final int PT_RGB = 4; + // Skipping other since we don't use them here + /////////////////////////////////////////////// + + // Conversion of predefined BufferedImage formats to LCMS formats + private static final int INT_RGB_LCMS_FMT = + colorspaceSh(PT_RGB)| + extraSh(1)| + channelsSh(3)| + bytesSh(1)| + doswapSh(1)| + swapfirstSh(1); + + private static final int INT_ARGB_LCMS_FMT = INT_RGB_LCMS_FMT; + + private static final int INT_BGR_LCMS_FMT = + colorspaceSh(PT_RGB)| + extraSh(1)| + channelsSh(3)| + bytesSh(1); + + private static final int THREE_BYTE_BGR_LCMS_FMT = + colorspaceSh(PT_RGB)| + channelsSh(3)| + bytesSh(1)| + doswapSh(1); + + private static final int FOUR_BYTE_ABGR_LCMS_FMT = + colorspaceSh(PT_RGB)| + extraSh(1)| + channelsSh(3)| + bytesSh(1)| + doswapSh(1); + + private static final int BYTE_GRAY_LCMS_FMT = + colorspaceSh(PT_GRAY)| + channelsSh(1)| + bytesSh(1); + + private static final int USHORT_GRAY_LCMS_FMT = + colorspaceSh(PT_GRAY)| + channelsSh(1)| + bytesSh(2); + + // LCMS format packed into 32 bit value. For description + // of this format refer to LCMS documentation. + private int cmmFormat = 0; + + // Dimensions + private int rows = 0; + private int cols = 0; + + // Scanline may contain some padding in the end + private int scanlineStride = -1; + + private Object imageData; + // It's possible to have offset from the beginning of the array + private int dataOffset; + + // Has the image alpha channel? If has - here its band band offset goes + private int alphaOffset = -1; + + // initializes proper field IDs + private static native void initIDs(); + + static { + NativeCMM.loadCMM(); + initIDs(); + } + + //////////////////////////////////// + // LCMS image format encoders + //////////////////////////////////// + private static int colorspaceSh(int s) { + return (s << 16); + } + + private static int swapfirstSh(int s) { + return (s << 14); + } + + private static int flavorSh(int s) { + return (s << 13); + } + + private static int planarSh(int s) { + return (s << 12); + } + + private static int endianSh(int s) { + return (s << 11); + } + + private static int doswapSh(int s) { + return (s << 10); + } + + private static int extraSh(int s) { + return (s << 7); + } + + private static int channelsSh(int s) { + return (s << 3); + } + + private static int bytesSh(int s) { + return s; + } + //////////////////////////////////// + // End of LCMS image format encoders + //////////////////////////////////// + + // Accessors + Object getChannelData() { + return imageData; + } + + int getNumCols() { + return cols; + } + + int getNumRows() { + return rows; + } + + // Constructors + public NativeImageFormat() { + } + + /** + * Simple image layout for common case with + * not optimized workflow. + * + * For hifi colorspaces with 5+ color channels imgData + * should be byte array. + * + * For common colorspaces with up to 4 color channels it + * should be short array. + * + * Alpha channel is handled by caller, not by CMS. + * + * Color channels are in their natural order (not BGR but RGB). + * + * @param imgData - array of byte or short + * @param nChannels - number of channels + * @param nRows - number of scanlines in the image + * @param nCols - number of pixels in one row of the image + */ + public NativeImageFormat(Object imgData, int nChannels, int nRows, int nCols) { + if (imgData instanceof short[]) { + cmmFormat |= bytesSh(2); + } + else if (imgData instanceof byte[]) { + cmmFormat |= bytesSh(1); + } + else + // awt.47=First argument should be byte or short array + throw new IllegalArgumentException(Messages.getString("awt.47")); //$NON-NLS-1$ + + cmmFormat |= channelsSh(nChannels); + + rows = nRows; + cols = nCols; + + imageData = imgData; + + dataOffset = 0; + } + + /** + * Deduces image format from the buffered image type + * or color and sample models. + * @param bi - image + * @return image format object + */ + public static NativeImageFormat createNativeImageFormat(BufferedImage bi) { + NativeImageFormat fmt = new NativeImageFormat(); + + switch (bi.getType()) { + case BufferedImage.TYPE_INT_RGB: { + fmt.cmmFormat = INT_RGB_LCMS_FMT; + break; + } + + case BufferedImage.TYPE_INT_ARGB: + case BufferedImage.TYPE_INT_ARGB_PRE: { + fmt.cmmFormat = INT_ARGB_LCMS_FMT; + fmt.alphaOffset = 3; + break; + } + + case BufferedImage.TYPE_INT_BGR: { + fmt.cmmFormat = INT_BGR_LCMS_FMT; + break; + } + + case BufferedImage.TYPE_3BYTE_BGR: { + fmt.cmmFormat = THREE_BYTE_BGR_LCMS_FMT; + break; + } + + case BufferedImage.TYPE_4BYTE_ABGR_PRE: + case BufferedImage.TYPE_4BYTE_ABGR: { + fmt.cmmFormat = FOUR_BYTE_ABGR_LCMS_FMT; + fmt.alphaOffset = 0; + break; + } + + case BufferedImage.TYPE_BYTE_GRAY: { + fmt.cmmFormat = BYTE_GRAY_LCMS_FMT; + break; + } + + case BufferedImage.TYPE_USHORT_GRAY: { + fmt.cmmFormat = USHORT_GRAY_LCMS_FMT; + break; + } + + case BufferedImage.TYPE_BYTE_BINARY: + case BufferedImage.TYPE_USHORT_565_RGB: + case BufferedImage.TYPE_USHORT_555_RGB: + case BufferedImage.TYPE_BYTE_INDEXED: { + // A bunch of unsupported formats + return null; + } + + default: + break; // Try to look at sample model and color model + } + + + if (fmt.cmmFormat == 0) { + ColorModel cm = bi.getColorModel(); + SampleModel sm = bi.getSampleModel(); + + if (sm instanceof ComponentSampleModel) { + ComponentSampleModel csm = (ComponentSampleModel) sm; + fmt.cmmFormat = getFormatFromComponentModel(csm, cm.hasAlpha()); + fmt.scanlineStride = calculateScanlineStrideCSM(csm, bi.getRaster()); + } else if (sm instanceof SinglePixelPackedSampleModel) { + SinglePixelPackedSampleModel sppsm = (SinglePixelPackedSampleModel) sm; + fmt.cmmFormat = getFormatFromSPPSampleModel(sppsm, cm.hasAlpha()); + fmt.scanlineStride = calculateScanlineStrideSPPSM(sppsm, bi.getRaster()); + } + + if (cm.hasAlpha()) + fmt.alphaOffset = calculateAlphaOffset(sm, bi.getRaster()); + } + + if (fmt.cmmFormat == 0) + return null; + + if (!fmt.setImageData(bi.getRaster().getDataBuffer())) { + return null; + } + + fmt.rows = bi.getHeight(); + fmt.cols = bi.getWidth(); + + fmt.dataOffset = bi.getRaster().getDataBuffer().getOffset(); + + return fmt; + } + + /** + * Deduces image format from the raster sample model. + * @param r - raster + * @return image format object + */ + public static NativeImageFormat createNativeImageFormat(Raster r) { + NativeImageFormat fmt = new NativeImageFormat(); + SampleModel sm = r.getSampleModel(); + + // Assume that there's no alpha + if (sm instanceof ComponentSampleModel) { + ComponentSampleModel csm = (ComponentSampleModel) sm; + fmt.cmmFormat = getFormatFromComponentModel(csm, false); + fmt.scanlineStride = calculateScanlineStrideCSM(csm, r); + } else if (sm instanceof SinglePixelPackedSampleModel) { + SinglePixelPackedSampleModel sppsm = (SinglePixelPackedSampleModel) sm; + fmt.cmmFormat = getFormatFromSPPSampleModel(sppsm, false); + fmt.scanlineStride = calculateScanlineStrideSPPSM(sppsm, r); + } + + if (fmt.cmmFormat == 0) + return null; + + fmt.cols = r.getWidth(); + fmt.rows = r.getHeight(); + fmt.dataOffset = r.getDataBuffer().getOffset(); + + if (!fmt.setImageData(r.getDataBuffer())) + return null; + + return fmt; + } + + /** + * Obtains LCMS format from the component sample model + * @param sm - sample model + * @param hasAlpha - true if there's an alpha channel + * @return LCMS format + */ + private static int getFormatFromComponentModel(ComponentSampleModel sm, boolean hasAlpha) { + // Multiple data arrays (banks) not supported + int bankIndex = sm.getBankIndices()[0]; + for (int i=1; i < sm.getNumBands(); i++) { + if (sm.getBankIndices()[i] != bankIndex) { + return 0; + } + } + + int channels = hasAlpha ? sm.getNumBands()-1 : sm.getNumBands(); + int extra = hasAlpha ? 1 : 0; + int bytes = 1; + switch (sm.getDataType()) { + case DataBuffer.TYPE_BYTE: + bytes = 1; break; + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: + bytes = 2; break; + case DataBuffer.TYPE_INT: + bytes = 4; break; + case DataBuffer.TYPE_DOUBLE: + bytes = 0; break; + default: + return 0; // Unsupported data type + } + + int doSwap = 0; + int swapFirst = 0; + boolean knownFormat = false; + + int i; + + // "RGBA" + for (i=0; i < sm.getNumBands(); i++) { + if (sm.getBandOffsets()[i] != i) break; + } + if (i == sm.getNumBands()) { // Ok, it is it + doSwap = 0; + swapFirst = 0; + knownFormat = true; + } + + // "ARGB" + if (!knownFormat) { + for (i=0; i < sm.getNumBands()-1; i++) { + if (sm.getBandOffsets()[i] != i+1) break; + } + if (sm.getBandOffsets()[i] == 0) i++; + if (i == sm.getNumBands()) { // Ok, it is it + doSwap = 0; + swapFirst = 1; + knownFormat = true; + } + } + + // "BGRA" + if (!knownFormat) { + for (i=0; i < sm.getNumBands()-1; i++) { + if (sm.getBandOffsets()[i] != sm.getNumBands() - 2 - i) break; + } + if (sm.getBandOffsets()[i] == sm.getNumBands()-1) i++; + if (i == sm.getNumBands()) { // Ok, it is it + doSwap = 1; + swapFirst = 1; + knownFormat = true; + } + } + + // "ABGR" + if (!knownFormat) { + for (i=0; i < sm.getNumBands(); i++) { + if (sm.getBandOffsets()[i] != sm.getNumBands() - 1 - i) break; + } + if (i == sm.getNumBands()) { // Ok, it is it + doSwap = 1; + swapFirst = 0; + knownFormat = true; + } + } + + // XXX - Planar formats are not supported yet + if (!knownFormat) + return 0; + + return + channelsSh(channels) | + bytesSh(bytes) | + extraSh(extra) | + doswapSh(doSwap) | + swapfirstSh(swapFirst); + } + + /** + * Obtains LCMS format from the single pixel packed sample model + * @param sm - sample model + * @param hasAlpha - true if there's an alpha channel + * @return LCMS format + */ + private static int getFormatFromSPPSampleModel(SinglePixelPackedSampleModel sm, + boolean hasAlpha) { + // Can we extract bytes? + int mask = sm.getBitMasks()[0] >>> sm.getBitOffsets()[0]; + if (!(mask == 0xFF || mask == 0xFFFF || mask == 0xFFFFFFFF)) + return 0; + + // All masks are same? + for (int i = 1; i < sm.getNumBands(); i++) { + if ((sm.getBitMasks()[i] >>> sm.getBitOffsets()[i]) != mask) + return 0; + } + + int pixelSize = 0; + // Check if data type is supported + if (sm.getDataType() == DataBuffer.TYPE_USHORT) + pixelSize = 2; + else if (sm.getDataType() == DataBuffer.TYPE_INT) + pixelSize = 4; + else + return 0; + + + int bytes = 0; + switch (mask) { + case 0xFF: + bytes = 1; + break; + case 0xFFFF: + bytes = 2; + break; + case 0xFFFFFFFF: + bytes = 4; + break; + default: return 0; + } + + + int channels = hasAlpha ? sm.getNumBands()-1 : sm.getNumBands(); + int extra = hasAlpha ? 1 : 0; + extra += pixelSize/bytes - sm.getNumBands(); // Unused bytes? + + // Form an ArrayList containing offset for each band + ArrayList offsetsLst = new ArrayList(); + for (int k=0; k < sm.getNumBands(); k++) { + offsetsLst.add(new Integer(sm.getBitOffsets()[k]/(bytes*8))); + } + + // Add offsets for unused space + for (int i=0; i + * + * xlfd format: + * -Foundry-Family-Weight-Slant-Width-Style-PixelSize-PointSize-ResX-ResY-Spacing-AvgWidth-Registry-Encoding + * @param xlfd String parameter in xlfd format + */ + public static String[] parseXLFD(String xlfd){ + int fieldsCount = 14; + String fieldsDelim = "-"; //$NON-NLS-1$ + String[] res = new String[fieldsCount]; + if (!xlfd.startsWith(fieldsDelim)){ + return null; + } + + xlfd = xlfd.substring(1); + int i=0; + int pos; + for (i=0; i < fieldsCount-1; i++){ + pos = xlfd.indexOf(fieldsDelim); + if (pos != -1){ + res[i] = xlfd.substring(0, pos); + xlfd = xlfd.substring(pos + 1); + } else { + return null; + } + } + pos = xlfd.indexOf(fieldsDelim); + + // check if no fields left + if(pos != -1){ + return null; + } + res[fieldsCount-1] = xlfd; + + return res; + } + + public int getFaceIndex(String faceName){ + + for (int i = 0; i < faces.length; i++) { + if(faces[i].equals(faceName)){ + return i; + } + } + return -1; + } + + public String[] getAllFamilies(){ + if (allFamilies == null){ + allFamilies = new String[]{"sans-serif", "serif", "monospace"}; + } + return allFamilies; + } + + public Font[] getAllFonts(){ + Font[] fonts = new Font[faces.length]; + for (int i =0; i < fonts.length;i++){ + fonts[i] = new Font(faces[i], Font.PLAIN, 1); + } + return fonts; + } + + public FontPeer createPhysicalFontPeer(String name, int style, int size) { + AndroidFont peer; + int familyIndex = getFamilyIndex(name); + if (familyIndex != -1){ + // !! we use family names from the list with cached families because + // they are differ from the family names in xlfd structure, in xlfd + // family names mostly in lower case. + peer = new AndroidFont(getFamily(familyIndex), style, size); + peer.setFamily(getFamily(familyIndex)); + return peer; + } + int faceIndex = getFaceIndex(name); + if (faceIndex != -1){ + + peer = new AndroidFont(name, style, size); + return peer; + } + + return null; + } + + public FontPeer createDefaultFont(int style, int size) { + Log.i("DEFAULT FONT", Integer.toString(style)); + return new AndroidFont(DEFAULT_NAME, style, size); + } + +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/font/AndroidFontProperty.java b/app/src/main/java/org/apache/harmony/awt/gl/font/AndroidFontProperty.java new file mode 100644 index 000000000..0cfdc43fc --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/font/AndroidFontProperty.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + * + */ +package org.apache.harmony.awt.gl.font; + +/** + * Android FontProperty implementation, applicable for Linux formats of + * font property files. + */ +public class AndroidFontProperty extends FontProperty { + + /** xlfd string that is applicable for Linux font.properties */ + String xlfd; + + /** logical name of the font corresponding to this FontProperty */ + String logicalName; + + /** style name of the font corresponding to this FontProperty */ + String styleName; + + public AndroidFontProperty(String _logicalName, String _styleName, String _fileName, String _name, String _xlfd, int _style, int[] exclusionRange, String _encoding){ + this.logicalName = _logicalName; + this.styleName = _styleName; + this.name = _name; + this.encoding = _encoding; + this.exclRange = exclusionRange; + this.fileName = _fileName; + this.xlfd = _xlfd; + this.style = _style; + } + + /** + * Returns logical name of the font corresponding to this FontProperty. + */ + public String getLogicalName(){ + return logicalName; + } + + /** + * Returns style name of the font corresponding to this FontProperty. + */ + public String getStyleName(){ + return styleName; + } + + /** + * Returns xlfd string of this FontProperty. + */ + public String getXLFD(){ + return xlfd; + } + + public String toString(){ + return new String(this.getClass().getName() + + "[name=" + name + //$NON-NLS-1$ + ",fileName="+ fileName + //$NON-NLS-1$ + ",Charset=" + encoding + //$NON-NLS-1$ + ",exclRange=" + exclRange + //$NON-NLS-1$ + ",xlfd=" + xlfd + "]"); //$NON-NLS-1$ //$NON-NLS-2$ + + } + +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/font/AndroidGlyphVector.java b/app/src/main/java/org/apache/harmony/awt/gl/font/AndroidGlyphVector.java new file mode 100644 index 000000000..f3b2e2871 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/font/AndroidGlyphVector.java @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.awt.gl.font; + +import com.android.internal.awt.AndroidGraphics2D; + +import java.awt.Font; +import java.awt.Shape; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphJustificationInfo; +import java.awt.font.GlyphMetrics; +import java.awt.font.GlyphVector; +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +import android.util.Log; +import android.graphics.Path; + +public class AndroidGlyphVector extends GlyphVector { + + // array of chars defined in constructor + public char[] charVector; + + // array of Glyph objects, that describe information about glyphs + public Glyph[] vector; + + // array of default positions of glyphs in GlyphVector + // without applying GlyphVector's transform + float[] defaultPositions; + + // array of logical positions of glyphs in GlyphVector + + float[] logicalPositions; + + // array of visual (real) positions of glyphs in GlyphVector + public float[] visualPositions; + + // FontRenderContext for this vector. + protected FontRenderContext vectorFRC; + + // layout flags mask + protected int layoutFlags = 0; + + // array of cached glyph outlines + protected Shape[] gvShapes; + + FontPeerImpl peer; + + // font corresponding to the GlyphVector + Font font; + + // ascent of the font + float ascent; + + // height of the font + float height; + + // leading of the font + float leading; + + // descent of the font + float descent; + + // transform of the GlyphVector + AffineTransform transform; + + @SuppressWarnings("deprecation") + public AndroidGlyphVector(char[] chars, FontRenderContext frc, Font fnt, + int flags) { + int len = chars.length; + this.font = fnt; + LineMetricsImpl lmImpl = (LineMetricsImpl)fnt.getLineMetrics(String.valueOf(chars), frc); + this.ascent = lmImpl.getAscent(); + this.height = lmImpl.getHeight(); + this.leading = lmImpl.getLeading(); + this.descent = lmImpl.getDescent(); + this.charVector = chars; + this.vectorFRC = frc; + } + + public AndroidGlyphVector(char[] chars, FontRenderContext frc, Font fnt) { + this(chars, frc, fnt, 0); + } + + public AndroidGlyphVector(String str, FontRenderContext frc, Font fnt) { + this(str.toCharArray(), frc, fnt, 0); + } + + public AndroidGlyphVector(String str, FontRenderContext frc, Font fnt, int flags) { + this(str.toCharArray(), frc, fnt, flags); + } + + @Override + public boolean equals(GlyphVector glyphVector) { + return false; + } + + public char[] getGlyphs() { + return this.charVector; + } + + @Override + public Font getFont() { + return this.font; + } + + @Override + public FontRenderContext getFontRenderContext() { + return this.vectorFRC; + } + + @Override + public int getGlyphCode(int glyphIndex) { + return charVector[glyphIndex]; + } + + @Override + public int[] getGlyphCodes(int beginGlyphIndex, int numEntries, + int[] codeReturn) { + throw new RuntimeException("Not implemented!"); + } + + @Override + public GlyphJustificationInfo getGlyphJustificationInfo(int glyphIndex) { + throw new RuntimeException("Not implemented!"); + } + + @Override + public Shape getGlyphLogicalBounds(int glyphIndex) { + throw new RuntimeException("Not implemented!"); + } + + @Override + public GlyphMetrics getGlyphMetrics(int glyphIndex) { + throw new RuntimeException("Not implemented!"); + } + + public Path getAndroidGlyphOutline(int glyphIndex) { + AndroidGraphics2D g = AndroidGraphics2D.getInstance(); + Path path = new Path(); + char tmp[] = new char[1]; + tmp[0] = charVector[glyphIndex]; + ((AndroidGraphics2D)g).getAndroidPaint().getTextPath(new String(tmp), 0, 1, 0, 0, path); + return path; + } + + @Override + public Shape getGlyphOutline(int glyphIndex) { + throw new RuntimeException("Not implemented!"); + } + + @Override + public Point2D getGlyphPosition(int glyphIndex) { + throw new RuntimeException("Not implemented!"); + } + + @Override + public float[] getGlyphPositions(int beginGlyphIndex, int numEntries, + float[] positionReturn) { + throw new RuntimeException("Not implemented!"); + } + + @Override + public AffineTransform getGlyphTransform(int glyphIndex) { + throw new RuntimeException("Not implemented!"); + } + + @Override + public Shape getGlyphVisualBounds(int glyphIndex) { + throw new RuntimeException("Not implemented!"); + } + + @Override + public Rectangle2D getLogicalBounds() { + throw new RuntimeException("Not implemented!"); + } + + @Override + public int getNumGlyphs() { + return charVector.length; + } + + @Override + public Shape getOutline(float x, float y) { + throw new RuntimeException("Not implemented!"); + } + + @Override + public Shape getOutline() { + throw new RuntimeException("Not implemented!"); + } + + public Path getAndroidOutline() { + AndroidGraphics2D g = AndroidGraphics2D.getInstance(); + Path path = new Path(); + ((AndroidGraphics2D)g).getAndroidPaint().getTextPath(new String(charVector), 0, charVector.length, 0, 0, path); + return path; + } + + @Override + public Rectangle2D getVisualBounds() { + throw new RuntimeException("Not implemented!"); + } + + @Override + public void performDefaultLayout() { + throw new RuntimeException("Not implemented!"); + } + + @Override + public void setGlyphPosition(int glyphIndex, Point2D newPos) { + throw new RuntimeException("Not implemented!"); + } + + @Override + public void setGlyphTransform(int glyphIndex, AffineTransform trans) { + throw new RuntimeException("Not implemented!"); + } + +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/font/AndroidLineMetrics.java b/app/src/main/java/org/apache/harmony/awt/gl/font/AndroidLineMetrics.java new file mode 100644 index 000000000..f37be6d4f --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/font/AndroidLineMetrics.java @@ -0,0 +1,120 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ +package org.apache.harmony.awt.gl.font; + +import java.awt.font.FontRenderContext; +import org.apache.harmony.awt.gl.font.LineMetricsImpl; + + +/** + * + * Linux implementation of LineMetrics class + */ +public class AndroidLineMetrics extends LineMetricsImpl { + + /** + * Constructor + */ + public AndroidLineMetrics( AndroidFont fnt, + FontRenderContext frc, + String str){ + numChars = str.length(); + baseLineIndex = 0; + + ascent = fnt.ascent; // Ascent of the font + descent = -fnt.descent; // Descent of the font + leading = fnt.leading; // External leading + + height = ascent + descent + leading; // Height of the font ( == (ascent + descent + leading)) + underlineThickness = 0.0f; + underlineOffset = 0.0f; + strikethroughThickness = 0.0f; + strikethroughOffset = 0.0f; + maxCharWidth = 0.0f; + + // TODO: Find out pixel metrics + /* + * positive metrics rounded to the smallest int that is bigger than value + * negative metrics rounded to the smallest int that is lesser than value + * thicknesses rounded to int ((int)round(value + 0.5)) + * + */ + + lAscent = (int)Math.ceil(fnt.ascent);// // Ascent of the font + lDescent = -(int)Math.ceil(fnt.descent);// Descent of the font + lLeading = (int)Math.ceil(leading); // External leading + + lHeight = lAscent + lDescent + lLeading; // Height of the font ( == (ascent + descent + leading)) + + lUnderlineThickness = Math.round(underlineThickness);//(int)metrics[11]; + + if (underlineOffset >= 0){ + lUnderlineOffset = (int)Math.ceil(underlineOffset); + } else { + lUnderlineOffset = (int)Math.floor(underlineOffset); + } + + lStrikethroughThickness = Math.round(strikethroughThickness); //(int)metrics[13]; + + if (strikethroughOffset >= 0){ + lStrikethroughOffset = (int)Math.ceil(strikethroughOffset); + } else { + lStrikethroughOffset = (int)Math.floor(strikethroughOffset); + } + + lMaxCharWidth = (int)Math.ceil(maxCharWidth); //(int)metrics[15]; + units_per_EM = 0; + + } + + public float[] getBaselineOffsets() { + // TODO: implement baseline offsets for TrueType fonts + if (baselineOffsets == null){ + float[] baselineData = null; + + // Temporary workaround: + // Commented out native data initialization, since it can + // cause failures with opening files in multithreaded applications. + // + // TODO: support work with truetype data in multithreaded + // applications. + + // If font TrueType data is taken from BASE table +// if ((this.font.getFontHandle() != 0) && (font.getFontType() == FontManager.FONT_TYPE_TT)){ +// baselineData = LinuxNativeFont.getBaselineOffsetsNative(font.getFontHandle(), font.getSize(), ascent, descent, units_per_EM); +// } +// + baseLineIndex = 0; + baselineOffsets = new float[]{0, (-ascent+descent)/2, -ascent}; + } + + return baselineOffsets; + } + + public int getBaselineIndex() { + if (baselineOffsets == null){ + // get offsets and set correct index + getBaselineOffsets(); + } + return baseLineIndex; + } + +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/font/BasicMetrics.java b/app/src/main/java/org/apache/harmony/awt/gl/font/BasicMetrics.java new file mode 100644 index 000000000..c0fb390f2 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/font/BasicMetrics.java @@ -0,0 +1,134 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + * + */ + +package org.apache.harmony.awt.gl.font; + +import java.awt.font.LineMetrics; +import java.awt.font.GraphicAttribute; +import java.awt.*; + +/** + * Date: May 14, 2005 + * Time: 7:44:13 PM + * + * This class incapsulates text metrics specific for the text layout or + * for the separate text segment. Text segment is a text run with the constant direction + * and attributes like font, decorations, etc. BasicMetrics is also used to store + * calculated text metrics like advance, ascent or descent. this class is very similar to + * LineMetrics, but provides some additional info, constructors and is more transparent. + */ +public class BasicMetrics { + int baseLineIndex; + + float ascent; // Ascent of the font + float descent; // Descent of the font + float leading; // External leading + float advance; + + float italicAngle; + float superScriptOffset; + + float underlineOffset; + float underlineThickness; + + float strikethroughOffset; + float strikethroughThickness; + + /** + * Constructs BasicMetrics from LineMetrics and font + * @param lm + * @param font + */ + BasicMetrics(LineMetrics lm, Font font) { + ascent = lm.getAscent(); + descent = lm.getDescent(); + leading = lm.getLeading(); + + underlineOffset = lm.getUnderlineOffset(); + underlineThickness = lm.getUnderlineThickness(); + + strikethroughOffset = lm.getStrikethroughOffset(); + strikethroughThickness = lm.getStrikethroughThickness(); + + baseLineIndex = lm.getBaselineIndex(); + + italicAngle = font.getItalicAngle(); + superScriptOffset = (float) font.getTransform().getTranslateY(); + } + + /** + * Constructs BasicMetrics from GraphicAttribute. + * It gets ascent and descent from the graphic attribute and + * computes reasonable defaults for other metrics. + * @param ga - graphic attribute + */ + BasicMetrics(GraphicAttribute ga) { + ascent = ga.getAscent(); + descent = ga.getDescent(); + leading = 2; + + baseLineIndex = ga.getAlignment(); + + italicAngle = 0; + superScriptOffset = 0; + + underlineOffset = Math.max(descent/2, 1); + + // Just suggested, should be cap_stem_width or something like that + underlineThickness = Math.max(ascent/13, 1); + + strikethroughOffset = -ascent/2; // Something like middle of the line + strikethroughThickness = underlineThickness; + } + + /** + * Copies metrics from the TextMetricsCalculator object. + * @param tmc - TextMetricsCalculator object + */ + BasicMetrics(TextMetricsCalculator tmc) { + ascent = tmc.ascent; + descent = tmc.descent; + leading = tmc.leading; + advance = tmc.advance; + baseLineIndex = tmc.baselineIndex; + } + + public float getAscent() { + return ascent; + } + + public float getDescent() { + return descent; + } + + public float getLeading() { + return leading; + } + + public float getAdvance() { + return advance; + } + + public int getBaseLineIndex() { + return baseLineIndex; + } +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/font/CaretManager.java b/app/src/main/java/org/apache/harmony/awt/gl/font/CaretManager.java new file mode 100644 index 000000000..3faf1b1f0 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/font/CaretManager.java @@ -0,0 +1,530 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + * + * @date: Jun 14, 2005 + */ + +package org.apache.harmony.awt.gl.font; + +import java.awt.font.TextHitInfo; +import java.awt.font.TextLayout; +import java.awt.geom.Rectangle2D; +import java.awt.geom.GeneralPath; +import java.awt.geom.Line2D; +import java.awt.*; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * This class provides functionality for creating caret and highlight shapes + * (bidirectional text is also supported, but, unfortunately, not tested yet). + */ +public class CaretManager { + private TextRunBreaker breaker; + + public CaretManager(TextRunBreaker breaker) { + this.breaker = breaker; + } + + /** + * Checks if TextHitInfo is not out of the text range and throws the + * IllegalArgumentException if it is. + * @param info - text hit info + */ + private void checkHit(TextHitInfo info) { + int idx = info.getInsertionIndex(); + + if (idx < 0 || idx > breaker.getCharCount()) { + // awt.42=TextHitInfo out of range + throw new IllegalArgumentException(Messages.getString("awt.42")); //$NON-NLS-1$ + } + } + + /** + * Calculates and returns visual position from the text hit info. + * @param hitInfo - text hit info + * @return visual index + */ + private int getVisualFromHitInfo(TextHitInfo hitInfo) { + final int idx = hitInfo.getCharIndex(); + + if (idx >= 0 && idx < breaker.getCharCount()) { + int visual = breaker.getVisualFromLogical(idx); + // We take next character for (LTR char + TRAILING info) and (RTL + LEADING) + if (hitInfo.isLeadingEdge() ^ ((breaker.getLevel(idx) & 0x1) == 0x0)) { + visual++; + } + return visual; + } else if (idx < 0) { + return breaker.isLTR() ? 0: breaker.getCharCount(); + } else { + return breaker.isLTR() ? breaker.getCharCount() : 0; + } + } + + /** + * Calculates text hit info from the visual position + * @param visual - visual position + * @return text hit info + */ + private TextHitInfo getHitInfoFromVisual(int visual) { + final boolean first = visual == 0; + + if (!(first || visual == breaker.getCharCount())) { + int logical = breaker.getLogicalFromVisual(visual); + return (breaker.getLevel(logical) & 0x1) == 0x0 ? + TextHitInfo.leading(logical) : // LTR + TextHitInfo.trailing(logical); // RTL + } else if (first) { + return breaker.isLTR() ? + TextHitInfo.trailing(-1) : + TextHitInfo.leading(breaker.getCharCount()); + } else { // Last + return breaker.isLTR() ? + TextHitInfo.leading(breaker.getCharCount()) : + TextHitInfo.trailing(-1); + } + } + + /** + * Creates caret info. Required for the getCaretInfo + * methods of the TextLayout + * @param hitInfo - specifies caret position + * @return caret info, see TextLayout.getCaretInfo documentation + */ + public float[] getCaretInfo(TextHitInfo hitInfo) { + checkHit(hitInfo); + float res[] = new float[2]; + + int visual = getVisualFromHitInfo(hitInfo); + float advance, angle; + TextRunSegment seg; + + if (visual < breaker.getCharCount()) { + int logIdx = breaker.getLogicalFromVisual(visual); + int segmentIdx = breaker.logical2segment[logIdx]; + seg = breaker.runSegments.get(segmentIdx); + advance = seg.x + seg.getAdvanceDelta(seg.getStart(), logIdx); + angle = seg.metrics.italicAngle; + + } else { // Last character + int logIdx = breaker.getLogicalFromVisual(visual-1); + int segmentIdx = breaker.logical2segment[logIdx]; + seg = breaker.runSegments.get(segmentIdx); + advance = seg.x + seg.getAdvanceDelta(seg.getStart(), logIdx+1); + } + + angle = seg.metrics.italicAngle; + + res[0] = advance; + res[1] = angle; + + return res; + } + + /** + * Returns the next position to the right from the current caret position + * @param hitInfo - current position + * @return next position to the right + */ + public TextHitInfo getNextRightHit(TextHitInfo hitInfo) { + checkHit(hitInfo); + int visual = getVisualFromHitInfo(hitInfo); + + if (visual == breaker.getCharCount()) { + return null; + } + + TextHitInfo newInfo; + + while(visual <= breaker.getCharCount()) { + visual++; + newInfo = getHitInfoFromVisual(visual); + + if (newInfo.getCharIndex() >= breaker.logical2segment.length) { + return newInfo; + } + + if (hitInfo.getCharIndex() >= 0) { // Don't check for leftmost info + if ( + breaker.logical2segment[newInfo.getCharIndex()] != + breaker.logical2segment[hitInfo.getCharIndex()] + ) { + return newInfo; // We crossed segment boundary + } + } + + TextRunSegment seg = breaker.runSegments.get(breaker.logical2segment[newInfo + .getCharIndex()]); + if (!seg.charHasZeroAdvance(newInfo.getCharIndex())) { + return newInfo; + } + } + + return null; + } + + /** + * Returns the next position to the left from the current caret position + * @param hitInfo - current position + * @return next position to the left + */ + public TextHitInfo getNextLeftHit(TextHitInfo hitInfo) { + checkHit(hitInfo); + int visual = getVisualFromHitInfo(hitInfo); + + if (visual == 0) { + return null; + } + + TextHitInfo newInfo; + + while(visual >= 0) { + visual--; + newInfo = getHitInfoFromVisual(visual); + + if (newInfo.getCharIndex() < 0) { + return newInfo; + } + + // Don't check for rightmost info + if (hitInfo.getCharIndex() < breaker.logical2segment.length) { + if ( + breaker.logical2segment[newInfo.getCharIndex()] != + breaker.logical2segment[hitInfo.getCharIndex()] + ) { + return newInfo; // We crossed segment boundary + } + } + + TextRunSegment seg = breaker.runSegments.get(breaker.logical2segment[newInfo + .getCharIndex()]); + if (!seg.charHasZeroAdvance(newInfo.getCharIndex())) { + return newInfo; + } + } + + return null; + } + + /** + * For each visual caret position there are two hits. For the simple LTR text one is + * a trailing of the previous char and another is the leading of the next char. This + * method returns the opposite hit for the given hit. + * @param hitInfo - given hit + * @return opposite hit + */ + public TextHitInfo getVisualOtherHit(TextHitInfo hitInfo) { + checkHit(hitInfo); + + int idx = hitInfo.getCharIndex(); + + int resIdx; + boolean resIsLeading; + + if (idx >= 0 && idx < breaker.getCharCount()) { // Hit info in the middle + int visual = breaker.getVisualFromLogical(idx); + + // Char is LTR + LEADING info + if (((breaker.getLevel(idx) & 0x1) == 0x0) ^ hitInfo.isLeadingEdge()) { + visual++; + if (visual == breaker.getCharCount()) { + if (breaker.isLTR()) { + resIdx = breaker.getCharCount(); + resIsLeading = true; + } else { + resIdx = -1; + resIsLeading = false; + } + } else { + resIdx = breaker.getLogicalFromVisual(visual); + if ((breaker.getLevel(resIdx) & 0x1) == 0x0) { + resIsLeading = true; + } else { + resIsLeading = false; + } + } + } else { + visual--; + if (visual == -1) { + if (breaker.isLTR()) { + resIdx = -1; + resIsLeading = false; + } else { + resIdx = breaker.getCharCount(); + resIsLeading = true; + } + } else { + resIdx = breaker.getLogicalFromVisual(visual); + if ((breaker.getLevel(resIdx) & 0x1) == 0x0) { + resIsLeading = false; + } else { + resIsLeading = true; + } + } + } + } else if (idx < 0) { // before "start" + if (breaker.isLTR()) { + resIdx = breaker.getLogicalFromVisual(0); + resIsLeading = (breaker.getLevel(resIdx) & 0x1) == 0x0; // LTR char? + } else { + resIdx = breaker.getLogicalFromVisual(breaker.getCharCount() - 1); + resIsLeading = (breaker.getLevel(resIdx) & 0x1) != 0x0; // RTL char? + } + } else { // idx == breaker.getCharCount() + if (breaker.isLTR()) { + resIdx = breaker.getLogicalFromVisual(breaker.getCharCount() - 1); + resIsLeading = (breaker.getLevel(resIdx) & 0x1) != 0x0; // LTR char? + } else { + resIdx = breaker.getLogicalFromVisual(0); + resIsLeading = (breaker.getLevel(resIdx) & 0x1) == 0x0; // RTL char? + } + } + + return resIsLeading ? TextHitInfo.leading(resIdx) : TextHitInfo.trailing(resIdx); + } + + public Line2D getCaretShape(TextHitInfo hitInfo, TextLayout layout) { + return getCaretShape(hitInfo, layout, true, false, null); + } + + /** + * Creates a caret shape. + * @param hitInfo - hit where to place a caret + * @param layout - text layout + * @param useItalic - unused for now, was used to create + * slanted carets for italic text + * @param useBounds - true if the cared should fit into the provided bounds + * @param bounds - bounds for the caret + * @return caret shape + */ + public Line2D getCaretShape( + TextHitInfo hitInfo, TextLayout layout, + boolean useItalic, boolean useBounds, Rectangle2D bounds + ) { + checkHit(hitInfo); + + float x1, x2, y1, y2; + + int charIdx = hitInfo.getCharIndex(); + + if (charIdx >= 0 && charIdx < breaker.getCharCount()) { + TextRunSegment segment = breaker.runSegments.get(breaker.logical2segment[charIdx]); + y1 = segment.metrics.descent; + y2 = - segment.metrics.ascent - segment.metrics.leading; + + x1 = x2 = segment.getCharPosition(charIdx) + (hitInfo.isLeadingEdge() ? + 0 : segment.getCharAdvance(charIdx)); + // Decided that straight cursor looks better even for italic fonts, + // especially combined with highlighting + /* + // Not graphics, need to check italic angle and baseline + if (layout.getBaseline() >= 0) { + if (segment.metrics.italicAngle != 0 && useItalic) { + x1 -= segment.metrics.italicAngle * segment.metrics.descent; + x2 += segment.metrics.italicAngle * + (segment.metrics.ascent + segment.metrics.leading); + + float baselineOffset = + layout.getBaselineOffsets()[layout.getBaseline()]; + y1 += baselineOffset; + y2 += baselineOffset; + } + } + */ + } else { + y1 = layout.getDescent(); + y2 = - layout.getAscent() - layout.getLeading(); + x1 = x2 = ((breaker.getBaseLevel() & 0x1) == 0 ^ charIdx < 0) ? + layout.getAdvance() : 0; + } + + if (useBounds) { + y1 = (float) bounds.getMaxY(); + y2 = (float) bounds.getMinY(); + + if (x2 > bounds.getMaxX()) { + x1 = x2 = (float) bounds.getMaxX(); + } + if (x1 < bounds.getMinX()) { + x1 = x2 = (float) bounds.getMinX(); + } + } + + return new Line2D.Float(x1, y1, x2, y2); + } + + /** + * Creates caret shapes for the specified offset. On the boundaries where + * the text is changing its direction this method may return two shapes + * for the strong and the weak carets, in other cases it would return one. + * @param offset - offset in the text. + * @param bounds - bounds to fit the carets into + * @param policy - caret policy + * @param layout - text layout + * @return one or two caret shapes + */ + public Shape[] getCaretShapes( + int offset, Rectangle2D bounds, + TextLayout.CaretPolicy policy, TextLayout layout + ) { + TextHitInfo hit1 = TextHitInfo.afterOffset(offset); + TextHitInfo hit2 = getVisualOtherHit(hit1); + + Shape caret1 = getCaretShape(hit1, layout); + + if (getVisualFromHitInfo(hit1) == getVisualFromHitInfo(hit2)) { + return new Shape[] {caret1, null}; + } + Shape caret2 = getCaretShape(hit2, layout); + + TextHitInfo strongHit = policy.getStrongCaret(hit1, hit2, layout); + return strongHit.equals(hit1) ? + new Shape[] {caret1, caret2} : + new Shape[] {caret2, caret1}; + } + + /** + * Connects two carets to produce a highlight shape. + * @param caret1 - 1st caret + * @param caret2 - 2nd caret + * @return highlight shape + */ + GeneralPath connectCarets(Line2D caret1, Line2D caret2) { + GeneralPath path = new GeneralPath(GeneralPath.WIND_NON_ZERO); + path.moveTo((float) caret1.getX1(), (float) caret1.getY1()); + path.lineTo((float) caret2.getX1(), (float) caret2.getY1()); + path.lineTo((float) caret2.getX2(), (float) caret2.getY2()); + path.lineTo((float) caret1.getX2(), (float) caret1.getY2()); + + path.closePath(); + + return path; + } + + /** + * Creates a highlight shape from given two hits. This shape + * will always be visually contiguous + * @param hit1 - 1st hit + * @param hit2 - 2nd hit + * @param bounds - bounds to fit the shape into + * @param layout - text layout + * @return highlight shape + */ + public Shape getVisualHighlightShape( + TextHitInfo hit1, TextHitInfo hit2, + Rectangle2D bounds, TextLayout layout + ) { + checkHit(hit1); + checkHit(hit2); + + Line2D caret1 = getCaretShape(hit1, layout, false, true, bounds); + Line2D caret2 = getCaretShape(hit2, layout, false, true, bounds); + + return connectCarets(caret1, caret2); + } + + /** + * Suppose that the user visually selected a block of text which has + * several different levels (mixed RTL and LTR), so, in the logical + * representation of the text this selection may be not contigous. + * This methods returns a set of logical ranges for the arbitrary + * visual selection represented by two hits. + * @param hit1 - 1st hit + * @param hit2 - 2nd hit + * @return logical ranges for the selection + */ + public int[] getLogicalRangesForVisualSelection(TextHitInfo hit1, TextHitInfo hit2) { + checkHit(hit1); + checkHit(hit2); + + int visual1 = getVisualFromHitInfo(hit1); + int visual2 = getVisualFromHitInfo(hit2); + + if (visual1 > visual2) { + int tmp = visual2; + visual2 = visual1; + visual1 = tmp; + } + + // Max level is 255, so we don't need more than 512 entries + int results[] = new int[512]; + + int prevLogical, logical, runStart, numRuns = 0; + + logical = runStart = prevLogical = breaker.getLogicalFromVisual(visual1); + + // Get all the runs. We use the fact that direction is constant in all runs. + for (int i=visual1+1; i<=visual2; i++) { + logical = breaker.getLogicalFromVisual(i); + int diff = logical-prevLogical; + + // Start of the next run encountered + if (diff > 1 || diff < -1) { + results[(numRuns)*2] = Math.min(runStart, prevLogical); + results[(numRuns)*2 + 1] = Math.max(runStart, prevLogical); + numRuns++; + runStart = logical; + } + + prevLogical = logical; + } + + // The last unsaved run + results[(numRuns)*2] = Math.min(runStart, logical); + results[(numRuns)*2 + 1] = Math.max(runStart, logical); + numRuns++; + + int retval[] = new int[numRuns*2]; + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(results, 0, retval, 0, numRuns*2); + return retval; + } + + /** + * Creates a highlight shape from given two endpoints in the logical + * representation. This shape is not always visually contiguous + * @param firstEndpoint - 1st logical endpoint + * @param secondEndpoint - 2nd logical endpoint + * @param bounds - bounds to fit the shape into + * @param layout - text layout + * @return highlight shape + */ + public Shape getLogicalHighlightShape( + int firstEndpoint, int secondEndpoint, + Rectangle2D bounds, TextLayout layout + ) { + GeneralPath res = new GeneralPath(); + + for (int i=firstEndpoint; i<=secondEndpoint; i++) { + int endRun = breaker.getLevelRunLimit(i, secondEndpoint); + TextHitInfo hit1 = TextHitInfo.leading(i); + TextHitInfo hit2 = TextHitInfo.trailing(endRun-1); + + Line2D caret1 = getCaretShape(hit1, layout, false, true, bounds); + Line2D caret2 = getCaretShape(hit2, layout, false, true, bounds); + + res.append(connectCarets(caret1, caret2), false); + + i = endRun; + } + + return res; + } +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/font/CommonGlyphVector.java b/app/src/main/java/org/apache/harmony/awt/gl/font/CommonGlyphVector.java new file mode 100644 index 000000000..90bb962fb --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/font/CommonGlyphVector.java @@ -0,0 +1,954 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ +package org.apache.harmony.awt.gl.font; + +import java.awt.Font; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphJustificationInfo; +import java.awt.font.GlyphMetrics; +import java.awt.font.GlyphVector; +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * GlyphVector implementation + */ +public class CommonGlyphVector extends GlyphVector { + + // array of transforms of glyphs in GlyphVector + protected AffineTransform[] glsTransforms; + + // array of chars defined in constructor + public char[] charVector; + + // array of Glyph objects, that describe information about glyphs + public Glyph[] vector; + + // array of default positions of glyphs in GlyphVector + // without applying GlyphVector's transform + float[] defaultPositions; + + // array of logical positions of glyphs in GlyphVector + + float[] logicalPositions; + + // array of visual (real) positions of glyphs in GlyphVector + public float[] visualPositions; + + // FontRenderContext for this vector. + protected FontRenderContext vectorFRC; + + // layout flags mask + protected int layoutFlags = 0; + + // array of cached glyph outlines + protected Shape[] gvShapes; + + FontPeerImpl peer; + + // font corresponding to the GlyphVector + Font font; + + // ascent of the font + float ascent; + + // height of the font + float height; + + // leading of the font + float leading; + + // descent of the font + float descent; + + // transform of the GlyphVector + AffineTransform transform; + + /** + * Creates new CommonGlyphVector object from the specified parameters. + * + * @param chars an array of chars + * @param frc FontRenderContext object + * @param fnt Font object + * @param flags layout flags + */ + @SuppressWarnings("deprecation") + public CommonGlyphVector(char[] chars, FontRenderContext frc, Font fnt, + int flags) { + int len = chars.length; + + this.font = fnt; + this.transform = fnt.getTransform(); + this.peer = (FontPeerImpl) fnt.getPeer(); + + gvShapes = new Shape[len]; + + // !! As pointed in API documentation for the + // getGlyphPosisitions(int index,int numEntries, float[] positionReturn) + // and getGlyphPosition(int index) methods, if the index is equals to + // the number of glyphs the position after the last glyph must be + // returned, thus there are n+1 positions and last (n+1) position + // points to the end of GlyphVector. + + logicalPositions = new float[(len+1)<<1]; + visualPositions = new float[(len+1)<<1]; + defaultPositions = new float[(len+1)<<1]; + + glsTransforms = new AffineTransform[len]; + + this.charVector = chars; + this.vectorFRC = frc; + //LineMetricsImpl lmImpl = (LineMetricsImpl)peer.getLineMetrics(); + + LineMetricsImpl lmImpl = (LineMetricsImpl)fnt.getLineMetrics(String.valueOf(chars), frc); + + this.ascent = lmImpl.getAscent(); + this.height = lmImpl.getHeight(); + this.leading = lmImpl.getLeading(); + this.descent = lmImpl.getDescent(); + this.layoutFlags = flags; + + if ((flags & Font.LAYOUT_RIGHT_TO_LEFT) != 0){ + char vector[] = new char[len]; + for(int i=0; i < len; i++){ + vector[i] = chars[len-i-1]; + } + this.vector = peer.getGlyphs(vector); + + } else { + this.vector = peer.getGlyphs(chars); + } + + this.glsTransforms = new AffineTransform[len]; + + setDefaultPositions(); + performDefaultLayout(); + } + + /** + * Creates new CommonGlyphVector object from the specified parameters. + * Layout flags set to default. + * + * @param chars an array of chars + * @param frc FontRenderContext object + * @param fnt Font object + */ + public CommonGlyphVector(char[] chars, FontRenderContext frc, Font fnt) { + this(chars, frc, fnt, 0); + } + + /** + * Creates new CommonGlyphVector object from the specified parameters. + * Layout flags set to default. + * + * @param str specified string + * @param frc FontRenderContext object + * @param fnt Font object + */ + public CommonGlyphVector(String str, FontRenderContext frc, Font fnt) { + this(str.toCharArray(), frc, fnt, 0); + } + + /** + * Creates new CommonGlyphVector object from the specified parameters. + * + * @param str specified string + * @param frc FontRenderContext object + * @param fnt Font object + * @param flags layout flags + */ + public CommonGlyphVector(String str, FontRenderContext frc, Font fnt, int flags) { + this(str.toCharArray(), frc, fnt, flags); + } + + /** + * Set array of logical positions of the glyphs to + * default with their default advances and height. + */ + void setDefaultPositions(){ + int len = getNumGlyphs(); + + // First [x,y] is set into [0,0] position + // for this reason start index is 1 + for (int i=1; i <= len; i++ ){ + int idx = i << 1; + float advanceX = vector[i-1].getGlyphPointMetrics().getAdvanceX(); + float advanceY = vector[i-1].getGlyphPointMetrics().getAdvanceY(); + + defaultPositions[idx] = defaultPositions[idx-2] + advanceX; + defaultPositions[idx+1] = defaultPositions[idx-1] + advanceY; + + } + transform.transform(defaultPositions, 0, logicalPositions, 0, getNumGlyphs()+1); + + } + + /** + * Returnes the pixel bounds of this GlyphVector rendered at the + * specified x,y location with the given FontRenderContext. + * + * @param frc a FontRenderContext that is used + * @param x specified x coordinate value + * @param y specified y coordinate value + * @return a Rectangle that bounds pixels of this GlyphVector + */ + @Override + public Rectangle getPixelBounds(FontRenderContext frc, float x, float y) { + + double xM, yM, xm, ym; + + double minX = 0; + double minY = 0; + double maxX = 0; + double maxY = 0; + + for (int i = 0; i < this.getNumGlyphs(); i++) { + Rectangle glyphBounds = this.getGlyphPixelBounds(i, frc, 0, 0); + xm = glyphBounds.getMinX(); + ym = glyphBounds.getMinY(); + xM = glyphBounds.getMaxX(); + yM = glyphBounds.getMaxY(); + + if (i == 0) { + minX = xm; + minY = ym; + maxX = xM; + maxY = yM; + } + + if (minX > xm) { + minX = xm; + } + if (minY > ym) { + minY = ym; + } + if (maxX < xM) { + maxX = xM; + } + if (maxY < yM) { + maxY = yM; + } + } + return new Rectangle((int)(minX + x), (int)(minY + y), (int)(maxX - minX), (int)(maxY - minY)); + + } + + /** + * Returns the visual bounds of this GlyphVector. + * The visual bounds is the bounds of the total outline of + * this GlyphVector. + * @return a Rectangle2D that id the visual bounds of this GlyphVector + */ + @Override + public Rectangle2D getVisualBounds() { + float xM, yM, xm, ym; + float minX = 0; + float minY = 0; + float maxX = 0; + float maxY = 0; + boolean firstIteration = true; + + for (int i = 0; i < this.getNumGlyphs(); i++) { + Rectangle2D bounds = this.getGlyphVisualBounds(i).getBounds2D(); + if (bounds.getWidth() == 0){ + continue; + } + xm = (float)bounds.getX(); + ym = (float)bounds.getY(); + + xM = (float)(xm + bounds.getWidth()); + + yM = ym + (float) bounds.getHeight(); + + if (firstIteration) { + minX = xm; + minY = ym; + maxX = xM; + maxY = yM; + firstIteration = false; + } else { + if (minX > xm) { + minX = xm; + } + if (minY > ym) { + minY = ym; + } + if (maxX < xM) { + maxX = xM; + } + if (maxY < yM) { + maxY = yM; + } + + } + } + + return (this.getNumGlyphs() != 0) ? new Rectangle2D.Float(minX, minY, + (maxX - minX), (maxY - minY)) : null; + } + + /** + * Sets new position to the specified glyph. + */ + @Override + public void setGlyphPosition(int glyphIndex, Point2D newPos) { + if ((glyphIndex > vector.length) || (glyphIndex < 0)) { + // awt.43=glyphIndex is out of vector's limits + throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$ + } + float x = (float)newPos.getX(); + float y = (float)newPos.getY(); + int index = glyphIndex << 1; + + if ((x != visualPositions[index]) || (y != visualPositions[index + 1])){ + visualPositions[index] = x; + visualPositions[index+1] = y; + layoutFlags = layoutFlags | FLAG_HAS_POSITION_ADJUSTMENTS; + } + + } + + /** + * Returns the position of the specified glyph relative to the origin of + * this GlyphVector + * @return a Point2D that the origin of the glyph with specified index + */ + @Override + public Point2D getGlyphPosition(int glyphIndex) { + if ((glyphIndex > vector.length) || (glyphIndex < 0)) { + // awt.43=glyphIndex is out of vector's limits + throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$ + } + int index = glyphIndex << 1; + Point2D pos = new Point2D.Float(visualPositions[index], visualPositions[index+1]); + + // For last position we don't have to transform !! + if(glyphIndex==vector.length){ + return pos; + } + + AffineTransform at = getGlyphTransform(glyphIndex); + if ((at == null) || (at.isIdentity())){ + return pos; + } + + pos.setLocation(pos.getX() + at.getTranslateX(), pos.getY() + at.getTranslateY()); + + return pos; + } + + /** + * Sets new transform to the specified glyph. + * + * @param glyphIndex specified index of the glyph + * @param trans AffineTransform of the glyph with specified index + */ + @Override + public void setGlyphTransform(int glyphIndex, AffineTransform trans) { + if ((glyphIndex >= vector.length) || (glyphIndex < 0)) { + // awt.43=glyphIndex is out of vector's limits + throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$ + } + + if ((trans == null) || (trans.isIdentity())) { + glsTransforms[glyphIndex] = null; + } else { + glsTransforms[glyphIndex] = new AffineTransform(trans); + layoutFlags = layoutFlags | FLAG_HAS_TRANSFORMS; + } + } + + /** + * Returns the affine transform of the specified glyph. + * + * @param glyphIndex specified index of the glyph + * @return an AffineTransform of the glyph with specified index + */ + @Override + public AffineTransform getGlyphTransform(int glyphIndex) { + if ((glyphIndex >= this.vector.length) || (glyphIndex < 0)) { + // awt.43=glyphIndex is out of vector's limits + throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$ + } + return this.glsTransforms[glyphIndex]; + } + + /** + * Returns the metrics of the specified glyph. + * + * @param glyphIndex specified index of the glyph + */ + @Override + public GlyphMetrics getGlyphMetrics(int glyphIndex) { + + if ((glyphIndex < 0) || ((glyphIndex) >= this.getNumGlyphs())) { + // awt.43=glyphIndex is out of vector's limits + throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$ + } + // TODO: is there a sence in GlyphMetrics + // if certain glyph or Font has a transform?? + return this.vector[glyphIndex].getGlyphMetrics(); + } + + /** + * Returns a justification information for the glyph with specified glyph + * index. + * @param glyphIndex index of a glyph which GlyphJustificationInfo is to be + * received + * @return a GlyphJustificationInfo object that contains glyph justification + * properties of the specified glyph + */ + @Override + public GlyphJustificationInfo getGlyphJustificationInfo(int glyphIndex) { + // TODO : Find out the source of Justification info + if (true) { + throw new RuntimeException("Method is not implemented"); //$NON-NLS-1$ + } + return null; + } + + /** + * Returns the FontRenderContext parameter of this GlyphVector. + */ + @Override + public FontRenderContext getFontRenderContext() { + return this.vectorFRC; + } + + /** + * Returns the visual bounds of the specified glyph. + * + * @param glyphIndex specified index of the glyph + */ + @Override + public Shape getGlyphVisualBounds(int glyphIndex) { + if ((glyphIndex < 0) || (glyphIndex >= this.getNumGlyphs())) { + // awt.43=glyphIndex is out of vector's limits + throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$ + } + + int idx = glyphIndex << 1; + + AffineTransform fontTransform = this.transform; + double xOffs = fontTransform.getTranslateX(); + double yOffs = fontTransform.getTranslateY(); + + if (vector[glyphIndex].getWidth() == 0){ + return new Rectangle2D.Float((float)xOffs, (float)yOffs, 0, 0); + } + + AffineTransform at = AffineTransform.getTranslateInstance(xOffs, yOffs); + AffineTransform glyphTransform = getGlyphTransform(glyphIndex); + + if (transform.isIdentity() && ((glyphTransform == null) || glyphTransform.isIdentity())){ + Rectangle2D blackBox = vector[glyphIndex].getGlyphMetrics().getBounds2D(); + at.translate(visualPositions[idx], visualPositions[idx+1]); + return(at.createTransformedShape(blackBox)); + } + + GeneralPath shape = (GeneralPath)this.getGlyphOutline(glyphIndex); + shape.transform(at); + return shape.getBounds2D(); + } + + /** + * Returnes the pixel bounds of the specified glyph within GlyphVector + * rendered at the specified x,y location. + * + * @param glyphIndex index of the glyph + * @param frc a FontRenderContext that is used + * @param x specified x coordinate value + * @param y specified y coordinate value + * @return a Rectangle that bounds pixels of the specified glyph + */ + @Override + public Rectangle getGlyphPixelBounds(int glyphIndex, FontRenderContext frc, + float x, float y) { + // TODO : need to be implemented with FontRenderContext + if ((glyphIndex < 0) || (glyphIndex >= this.getNumGlyphs())) { + // awt.43=glyphIndex is out of vector's limits + throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$ + } + + int idx = glyphIndex << 1; + + if (vector[glyphIndex].getWidth() == 0){ + AffineTransform fontTransform = this.transform; + double xOffs = x + visualPositions[idx] + fontTransform.getTranslateX(); + double yOffs = y + visualPositions[idx+1] + fontTransform.getTranslateY(); + return new Rectangle((int)xOffs, (int)yOffs, 0, 0); + } + + GeneralPath shape = (GeneralPath)this.getGlyphOutline(glyphIndex); + + AffineTransform at = AffineTransform.getTranslateInstance(x, y); + + if (frc != null){ + at.concatenate(frc.getTransform()); + } + + shape.transform(at); + + Rectangle bounds = shape.getBounds(); + return new Rectangle((int)bounds.getX(), (int)bounds.getY(), + (int)bounds.getWidth()-1, (int)bounds.getHeight()-1); + } + + /** + * Returns a Shape that encloses specified glyph. + * + * @param glyphIndex specified index of the glyph + */ + @Override + public Shape getGlyphOutline(int glyphIndex) { + if ((glyphIndex < 0) || (glyphIndex >= this.getNumGlyphs())) { + // awt.43=glyphIndex is out of vector's limits + throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$ + } + + if (gvShapes[glyphIndex] == null) { + gvShapes[glyphIndex] = vector[glyphIndex].getShape(); + } + + GeneralPath gp = (GeneralPath)((GeneralPath)gvShapes[glyphIndex]).clone(); + + /* Applying GlyphVector font transform */ + AffineTransform at = (AffineTransform)this.transform.clone(); + + /* Applying Glyph transform */ + AffineTransform glyphAT = getGlyphTransform(glyphIndex); + if (glyphAT != null){ + at.preConcatenate(glyphAT); + } + + int idx = glyphIndex << 1; + + gp.transform(at); + gp.transform(AffineTransform.getTranslateInstance(visualPositions[idx], visualPositions[idx+1])); + return gp; + } + + + /** + * Returns a Shape that is the outline representation of this GlyphVector + * rendered at the specified x,y coordinates. + * + * @param x specified x coordinate value + * @param y specified y coordinate value + * @return a Shape object that is the outline of this GlyphVector + * at the specified coordinates. + */ + @Override + public Shape getOutline(float x, float y) { + GeneralPath gp = new GeneralPath(GeneralPath.WIND_EVEN_ODD); + for (int i = 0; i < this.vector.length; i++) { + GeneralPath outline = (GeneralPath)getGlyphOutline(i); + + /* Applying translation to actual visual bounds */ + outline.transform(AffineTransform.getTranslateInstance(x, y)); + gp.append(outline, false); + } + + return gp; + } + + /** + * Returns a Shape that is the outline representation of this GlyphVector. + * + * @return a Shape object that is the outline of this GlyphVector + */ + @Override + public Shape getOutline() { + return this.getOutline(0, 0); + } + + /** + * Returns an array of glyphcodes for the specified glyphs. + * + * @param beginGlyphIndex the start index + * @param numEntries the number of glyph codes to get + * @param codeReturn the array that receives glyph codes' values + * @return an array that receives glyph codes' values + */ + @Override + public int[] getGlyphCodes(int beginGlyphIndex, int numEntries, + int[] codeReturn) { + + if ((beginGlyphIndex < 0) || ((numEntries + beginGlyphIndex) > this.getNumGlyphs())) { + // awt.44=beginGlyphIndex is out of vector's range + throw new IndexOutOfBoundsException(Messages.getString("awt.44")); //$NON-NLS-1$ + } + + if (numEntries < 0) { + // awt.45=numEntries is out of vector's range + throw new IllegalArgumentException(Messages.getString("awt.45")); //$NON-NLS-1$ + } + + if (codeReturn == null) { + codeReturn = new int[numEntries]; + } + + for (int i = beginGlyphIndex; i < beginGlyphIndex + numEntries; i++) { + codeReturn[i-beginGlyphIndex] = this.vector[i].getGlyphCode(); + } + + return codeReturn; + } + + /** + * Returns an array of numEntries character indices for the specified glyphs. + * + * @param beginGlyphIndex the start index + * @param numEntries the number of glyph codes to get + * @param codeReturn the array that receives glyph codes' values + * @return an array that receives glyph char indices + */ + @Override + public int[] getGlyphCharIndices(int beginGlyphIndex, int numEntries, + int[] codeReturn) { + if ((beginGlyphIndex < 0) || (beginGlyphIndex >= this.getNumGlyphs())) { + // awt.44=beginGlyphIndex is out of vector's range + throw new IllegalArgumentException(Messages.getString("awt.44")); //$NON-NLS-1$ + } + + if ((numEntries < 0) + || ((numEntries + beginGlyphIndex) > this.getNumGlyphs())) { + // awt.45=numEntries is out of vector's range + throw new IllegalArgumentException(Messages.getString("awt.45")); //$NON-NLS-1$ + } + + if (codeReturn == null) { + codeReturn = new int[numEntries]; + } + + for (int i = 0; i < numEntries; i++) { + codeReturn[i] = this.getGlyphCharIndex(i + beginGlyphIndex); + } + return codeReturn; + } + + /** + * Returns an array of numEntries glyphs positions from beginGlyphIndex + * glyph in Glyph Vector. + * + * @param beginGlyphIndex the start index + * @param numEntries the number of glyph codes to get + * @param positionReturn the array that receives glyphs' positions + * @return an array of floats that receives glyph char indices + */ + @Override + public float[] getGlyphPositions(int beginGlyphIndex, int numEntries, + float[] positionReturn) { + + int len = (this.getNumGlyphs()+1) << 1; + beginGlyphIndex *= 2; + numEntries *= 2; + + if ((beginGlyphIndex < 0) || ((numEntries + beginGlyphIndex) > len)) { + // awt.44=beginGlyphIndex is out of vector's range + throw new IndexOutOfBoundsException(Messages.getString("awt.44")); //$NON-NLS-1$ + } + + if (numEntries < 0) { + // awt.45=numEntries is out of vector's range + throw new IllegalArgumentException(Messages.getString("awt.45")); //$NON-NLS-1$ + } + + if (positionReturn == null) { + positionReturn = new float[numEntries]; + } + + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(visualPositions, beginGlyphIndex, positionReturn, 0, numEntries); + + return positionReturn; + } + + /** + * Set numEntries elements of the visualPositions array from beginGlyphIndex + * of numEntries glyphs positions from beginGlyphIndex glyph in Glyph Vector. + * + * @param beginGlyphIndex the start index + * @param numEntries the number of glyph codes to get + * @param setPositions the array of positions to set + */ + public void setGlyphPositions(int beginGlyphIndex, int numEntries, + float[] setPositions) { + + int len = (this.getNumGlyphs()+1) << 1; + beginGlyphIndex *= 2; + numEntries *= 2; + + if ((beginGlyphIndex < 0) || ((numEntries + beginGlyphIndex) > len)) { + // awt.44=beginGlyphIndex is out of vector's range + throw new IndexOutOfBoundsException(Messages.getString("awt.44")); //$NON-NLS-1$ + } + + if (numEntries < 0) { + // awt.45=numEntries is out of vector's range + throw new IllegalArgumentException(Messages.getString("awt.45")); //$NON-NLS-1$ + } + + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(setPositions, 0, visualPositions, beginGlyphIndex, numEntries); + layoutFlags = layoutFlags & FLAG_HAS_POSITION_ADJUSTMENTS; + + } + + /** + * Set elements of the visualPositions array. + * + * @param setPositions the array of positions to set + */ + public void setGlyphPositions(float[] setPositions) { + + int len = (this.getNumGlyphs()+1) << 1; + if (len != setPositions.length){ + // awt.46=length of setPositions array differs from the length of positions array + throw new IllegalArgumentException(Messages.getString("awt.46")); //$NON-NLS-1$ + } + + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(setPositions, 0, visualPositions, 0, len); + layoutFlags = layoutFlags & FLAG_HAS_POSITION_ADJUSTMENTS; + + } + + + /** + * Returns glyph code of the specified glyph. + * + * @param glyphIndex specified index of the glyph + */ + @Override + public int getGlyphCode(int glyphIndex) { + if (glyphIndex >= this.vector.length || glyphIndex < 0) { + // awt.43=glyphIndex is out of vector's limits + throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$ + } + return this.vector[glyphIndex].getGlyphCode(); + } + + /** + * Returns character index of the specified glyph. + * + * @param glyphIndex specified index of the glyph + */ + @Override + public int getGlyphCharIndex(int glyphIndex) { + + if ((glyphIndex < 0) || (glyphIndex >= this.getNumGlyphs())) { + // awt.43=glyphIndex is out of vector's limits + throw new IllegalArgumentException(Messages.getString("awt.43")); //$NON-NLS-1$ + } + + if ((this.layoutFlags & Font.LAYOUT_RIGHT_TO_LEFT) != 0) { + return this.charVector.length - glyphIndex - 1; + } + + return glyphIndex; + } + + /** + * Returns a character value of the specified glyph. + * + * @param glyphIndex specified index of the glyph + */ + public char getGlyphChar(int glyphIndex) { + + if ((glyphIndex < 0) || (glyphIndex >= this.getNumGlyphs())) { + // awt.43=glyphIndex is out of vector's limits + throw new IllegalArgumentException(Messages.getString("awt.43")); //$NON-NLS-1$ + } + return this.charVector[glyphIndex]; + } + + /** + * Assigns default positions to each glyph in this GlyphVector. + */ + @Override + public void performDefaultLayout() { + + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(logicalPositions, 0, visualPositions, 0, logicalPositions.length); + + // Set position changes flag to zero + clearLayoutFlags(GlyphVector.FLAG_HAS_POSITION_ADJUSTMENTS); + } + + /** + * Returns the number of glyphs in this Glyph Vector + */ + @Override + public int getNumGlyphs() { + return vector.length; + } + + /** + * Returns the logical bounds of this GlyphVector + */ + @Override + public Rectangle2D getLogicalBounds(){ + // XXX: for transforms where an angle between basis vectors is not 90 degrees + // Rectanlge2D class doesn't fit as Logical bounds. For this reason we use + // only non-transformed bounds!! + + float x = visualPositions[0]; + float width = visualPositions[visualPositions.length-2]; + + double scaleY = transform.getScaleY(); + + Rectangle2D bounds = new Rectangle2D.Float(x, (float)((-this.ascent-this.leading)*scaleY), width, (float)(this.height*scaleY)); + return bounds; + } + + + /** + * Checks whether given GlyphVector equals to this GlyphVector. + * @param glyphVector GlyphVector object to compare + */ + @Override + public boolean equals(GlyphVector glyphVector){ + if (glyphVector == this){ + return true; + } + + if (glyphVector != null) { + + if (!(glyphVector.getFontRenderContext().equals(this.vectorFRC) && + glyphVector.getFont().equals(this.font))){ + return false; + } + + try { + boolean eq = true; + for (int i = 0; i < getNumGlyphs(); i++) { + + int idx = i*2; + eq = (((CommonGlyphVector)glyphVector).visualPositions[idx] == this.visualPositions[idx]) && + (((CommonGlyphVector)glyphVector).visualPositions[idx+1] == this.visualPositions[idx+1]) && + (glyphVector.getGlyphCharIndex(i) == this.getGlyphCharIndex(i)); + + if (eq){ + AffineTransform trans = glyphVector.getGlyphTransform(i); + if (trans == null){ + eq = (this.glsTransforms[i] == null); + }else{ + eq = this.glsTransforms[i].equals(trans); + } + } + + if (!eq){ + return false; + } + } + + return eq; + } catch (ClassCastException e) { + } + } + + return false; + } + + + /** + * Returns flags describing the state of the GlyphVector. + */ + @Override + public int getLayoutFlags() { + return layoutFlags; + } + + /** + * Returns char with the specified index. + * + * @param index specified index of the char + * + */ + public char getChar(int index) { + return this.charVector[index]; + + } + + /** + * Clear desired flags in layout flags describing the state. + * + * @param clearFlags flags mask to clear + */ + + private void clearLayoutFlags(int clearFlags){ + layoutFlags &= ~clearFlags; + } + + /** + * Returns the logical bounds of the specified glyph within this CommonGlyphVector. + * + * @param glyphIndex index of the glyph to get it's logical bounds + * @return logical bounds of the specified glyph + */ + @Override + public Shape getGlyphLogicalBounds(int glyphIndex){ + if ((glyphIndex < 0) || (glyphIndex >= this.getNumGlyphs())){ + // awt.43=glyphIndex is out of vector's limits + throw new IndexOutOfBoundsException(Messages.getString("awt.43")); //$NON-NLS-1$ + } + Glyph glyph = this.vector[glyphIndex]; + + float x0 = visualPositions[glyphIndex*2]; + float y0 = visualPositions[glyphIndex*2+1]; + float advanceX = glyph.getGlyphPointMetrics().getAdvanceX(); + + GeneralPath gp = new GeneralPath(); + gp.moveTo(0, -ascent - leading); + gp.lineTo(advanceX ,-ascent - leading); + gp.lineTo(advanceX, descent); + gp.lineTo(0, descent); + gp.lineTo(0, -ascent - leading); + gp.closePath(); + + /* Applying GlyphVector font transform */ + AffineTransform at = (AffineTransform)this.transform.clone(); + + /* Applying Glyph transform */ + AffineTransform glyphTransform = getGlyphTransform(glyphIndex); + if (glyphTransform != null){ + at.concatenate(glyphTransform); + } + + /* Applying translation to actual visual bounds */ + at.preConcatenate(AffineTransform.getTranslateInstance(x0, y0)); + gp.transform(at); + return gp; + } + + /** + * Returns the Font parameter of this GlyphVector + */ + @Override + public Font getFont(){ + return this.font; + } + + +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/font/CompositeFont.java b/app/src/main/java/org/apache/harmony/awt/gl/font/CompositeFont.java new file mode 100644 index 000000000..70cb3341b --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/font/CompositeFont.java @@ -0,0 +1,486 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ +package org.apache.harmony.awt.gl.font; + +import java.awt.font.FontRenderContext; +import java.awt.font.LineMetrics; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; + +import org.apache.harmony.awt.gl.font.FontPeerImpl; +import org.apache.harmony.awt.gl.font.FontProperty; + +/** + * CompositeFont class is the implementation of logical font classes. + * Every logical font consists of several physical fonts that described + * in font.properties file according to the face name of this logical font. + */ +public class CompositeFont extends FontPeerImpl{ + + // a number of physical fonts that CompositeFont consist of + int numFonts; + + // font family name + String family; + + // font face name + String face; + + String[] fontNames; + + // an array of font properties applicable to this CompositeFont + FontProperty[] fontProperties; + + // an array of font peers applicable to this CompositeFont + public FontPeerImpl[] fPhysicalFonts; + + // missing glyph code field + int missingGlyphCode = -1; + + // line metrics of this font + LineMetricsImpl nlm = null; + + // cached num glyphs parameter of this font that is the sum of num glyphs of + // font peers composing this font + int cachedNumGlyphs = -1; + /** + * Creates CompositeFont object that is corresponding to the specified logical + * family name. + * + * @param familyName logical family name CompositeFont is to be created from + * @param faceName logical face name CompositeFont is to be created from + * @param _style style of the CompositeFont to be created + * @param _size size of the CompositeFont to be created + * @param fProperties an array of FontProperties describing physical fonts - + * parts of logical font + * @param physFonts an array of physical font peers related to the CompositeFont + * to be created + */ + public CompositeFont(String familyName, String faceName, int _style, int _size, FontProperty[] fProperties, FontPeerImpl[] physFonts){ + this.size = _size; + this.name = faceName; + this.family = familyName; + this.style = _style; + this.face = faceName; + this.psName = faceName; + this.fontProperties = fProperties;// !! Supposed that fProperties parameter != null + fPhysicalFonts = physFonts; + numFonts = fPhysicalFonts.length; + setDefaultLineMetrics("", null); //$NON-NLS-1$ + this.uniformLM = false; + } + + /** + * Returns the index of the FontPeer in array of physical fonts that is applicable + * for the given character. This font has to have the highest priority among fonts + * that can display this character and don't have exclusion range covering + * specified character. If there is no desired fonts -1 is returned. + * + * @param chr specified character + * @return index of the font from the array of physical fonts that will be used + * during processing of the specified character. + */ + public int getCharFontIndex(char chr){ + for (int i = 0; i < numFonts; i++){ + if (fontProperties[i].isCharExcluded(chr)){ + continue; + } + if (fPhysicalFonts[i].canDisplay(chr)){ + return i; + } + } + + return -1; + } + + /** + * Returns the index of the FontPeer in array of physical fonts that is applicable + * for the given character. This font has to have the highest priority among fonts + * that can display this character and don't have exclusion range covering + * specified character. If there is no desired fonts default value is returned. + * + * @param chr specified character + * @param defaultValue default index that is returned if the necessary font couldn't be found. + * @return index of the font from the array of physical fonts that will be used + * during processing of the specified character. + */ + public int getCharFontIndex(char chr, int defaultValue){ + for (int i = 0; i < numFonts; i++){ + if (fontProperties[i].isCharExcluded(chr)){ + continue; + } + if (fPhysicalFonts[i].canDisplay(chr)){ + return i; + } + } + + return defaultValue; + } + + /** + * Returns true if one of the physical fonts composing this font CompositeFont + * can display specified character. + * + * @param chr specified character + */ + @Override + public boolean canDisplay(char chr){ + return (getCharFontIndex(chr) != -1); + } + + /** + * Returns logical ascent (in pixels) + */ + @Override + public int getAscent(){ + return nlm.getLogicalAscent(); + } + + /** + * Returns LineMetrics instance scaled according to the specified transform. + * + * @param str specified String + * @param frc specified FontRenderContext + * @param at specified AffineTransform + */ + @Override + public LineMetrics getLineMetrics(String str, FontRenderContext frc , AffineTransform at){ + LineMetricsImpl lm = (LineMetricsImpl)(this.nlm.clone()); + lm.setNumChars(str.length()); + + if ((at != null) && (!at.isIdentity())){ + lm.scale((float)at.getScaleX(), (float)at.getScaleY()); + } + + return lm; + } + + /** + * Returns cached LineMetrics instance for the null string or creates it if + * it wasn't cached yet. + */ + @Override + public LineMetrics getLineMetrics(){ + if (nlm == null){ + setDefaultLineMetrics("", null); //$NON-NLS-1$ + } + + return this.nlm; + } + + /** + * Creates LineMetrics instance and set cached LineMetrics field to it. + * Created LineMetrics has maximum values of the idividual metrics of all + * composing physical fonts. If there is only one physical font - it's + * LineMetrics object is returned. + * + * @param str specified String + * @param frc specified FontRenderContext + */ + private void setDefaultLineMetrics(String str, FontRenderContext frc){ + LineMetrics lm = fPhysicalFonts[0].getLineMetrics(str, frc, null); + float maxCharWidth = (float)fPhysicalFonts[0].getMaxCharBounds(frc).getWidth(); + + if (numFonts == 1) { + this.nlm = (LineMetricsImpl)lm; + return; + } + + float[] baselineOffsets = lm.getBaselineOffsets(); + int numChars = str.length(); + + // XXX: default value - common for all Fonts + int baseLineIndex = lm.getBaselineIndex(); + + float maxUnderlineThickness = lm.getUnderlineThickness(); + float maxUnderlineOffset = lm.getUnderlineOffset(); + float maxStrikethroughThickness = lm.getStrikethroughThickness(); + float minStrikethroughOffset = lm.getStrikethroughOffset(); + float maxLeading = lm.getLeading(); // External leading + float maxHeight = lm.getHeight(); // Height of the font ( == (ascent + descent + leading)) + float maxAscent = lm.getAscent(); // Ascent of the font + float maxDescent = lm.getDescent(); // Descent of the font + + for (int i = 1; i < numFonts; i++){ + lm = fPhysicalFonts[i].getLineMetrics(str, frc, null); + if (maxUnderlineThickness < lm.getUnderlineThickness()){ + maxUnderlineThickness = lm.getUnderlineThickness(); + } + + if (maxUnderlineOffset < lm.getUnderlineOffset()){ + maxUnderlineOffset = lm.getUnderlineOffset(); + } + + if (maxStrikethroughThickness < lm.getStrikethroughThickness()){ + maxStrikethroughThickness = lm.getStrikethroughThickness(); + } + + if (minStrikethroughOffset > lm.getStrikethroughOffset()){ + minStrikethroughOffset = lm.getStrikethroughOffset(); + } + + if (maxLeading < lm.getLeading()){ + maxLeading = lm.getLeading(); + } + + if (maxAscent < lm.getAscent()){ + maxAscent = lm.getAscent(); + } + + if (maxDescent < lm.getDescent()){ + maxDescent = lm.getDescent(); + } + + float width = (float)fPhysicalFonts[i].getMaxCharBounds(frc).getWidth(); + if(maxCharWidth < width){ + maxCharWidth = width; + } + for (int j =0; j < baselineOffsets.length; j++){ + float[] offsets = lm.getBaselineOffsets(); + if (baselineOffsets[j] > offsets[j]){ + baselineOffsets[j] = offsets[j]; + } + } + + } + maxHeight = maxAscent + maxDescent + maxLeading; + + this.nlm = new LineMetricsImpl( + numChars, + baseLineIndex, + baselineOffsets, + maxUnderlineThickness, + maxUnderlineOffset, + maxStrikethroughThickness, + minStrikethroughOffset, + maxLeading, + maxHeight, + maxAscent, + maxDescent, + maxCharWidth); + + } + + /** + * Returns the number of glyphs in this CompositeFont object. + */ + @Override + public int getNumGlyphs(){ + if (this.cachedNumGlyphs == -1){ + + this.cachedNumGlyphs = 0; + + for (int i = 0; i < numFonts; i++){ + this.cachedNumGlyphs += fPhysicalFonts[i].getNumGlyphs(); + } + } + + return this.cachedNumGlyphs; + } + + /** + * Returns the italic angle of this object. + */ + @Override + public float getItalicAngle(){ + // !! only first physical font used to get this value + return fPhysicalFonts[0].getItalicAngle(); + } + + /** + * Returns rectangle that bounds the specified string in terms of composite line metrics. + * + * @param chars an array of chars + * @param start the initial offset in array of chars + * @param end the end offset in array of chars + * @param frc specified FontRenderContext + */ + public Rectangle2D getStringBounds(char[] chars, int start, int end, FontRenderContext frc){ + + LineMetrics lm = getLineMetrics(); + float minY = -lm.getAscent(); + float minX = 0; + float height = lm.getHeight(); + float width = 0; + + for (int i = start; i < end; i++){ + width += charWidth(chars[i]); + } + + Rectangle2D rect2D = new Rectangle2D.Float(minX, minY, width, height); + return rect2D; + + } + + /** + * Returns maximum rectangle that encloses all maximum char bounds of + * physical fonts composing this CompositeFont. + * + * @param frc specified FontRenderContext + */ + @Override + public Rectangle2D getMaxCharBounds(FontRenderContext frc){ + + Rectangle2D rect2D = fPhysicalFonts[0].getMaxCharBounds(frc); + float minY = (float)rect2D.getY(); + float maxWidth = (float)rect2D.getWidth(); + float maxHeight = (float)rect2D.getHeight(); + if (numFonts == 1){ + return rect2D; + } + + for (int i = 1; i < numFonts; i++){ + if (fPhysicalFonts[i] != null){ + rect2D = fPhysicalFonts[i].getMaxCharBounds(frc); + float y = (float)rect2D.getY(); + float mWidth = (float)rect2D.getWidth(); + float mHeight = (float)rect2D.getHeight(); + if (y < minY){ + minY = y; + } + if (mWidth > maxWidth){ + maxHeight = mWidth; + } + + if (mHeight > maxHeight){ + maxHeight = mHeight; + } + } + } + + rect2D = new Rectangle2D.Float(0, minY, maxWidth, maxHeight); + + return rect2D; + } + + /** + * Returns font name. + */ + @Override + public String getFontName(){ + return face; + } + + /** + * Returns font postscript name. + */ + @Override + public String getPSName(){ + return psName; + } + + /** + * Returns font family name. + */ + @Override + public String getFamily(){ + return family; + } + + /** + * Returns the code of the missing glyph. + */ + @Override + public int getMissingGlyphCode(){ + // !! only first physical font used to get this value + return fPhysicalFonts[0].getMissingGlyphCode(); + } + + /** + * Returns Glyph object corresponding to the specified character. + * + * @param ch specified char + */ + @Override + public Glyph getGlyph(char ch){ + for (int i = 0; i < numFonts; i++){ + if (fontProperties[i].isCharExcluded(ch)){ + continue; + } + + /* Control symbols considered to be supported by the font peer */ + if ((ch < 0x20) || fPhysicalFonts[i].canDisplay(ch)){ + return fPhysicalFonts[i].getGlyph(ch); + } + } + return getDefaultGlyph(); + } + + /** + * Returns width of the char with specified index. + * + * @param ind specified index of the character + */ + @Override + public int charWidth(int ind){ + return charWidth((char)ind); + } + + /** + * Returns width of the specified char. + * + * @param c specified character + */ + @Override + public int charWidth(char c){ + Glyph gl = this.getGlyph(c); + return (int)gl.getGlyphPointMetrics().getAdvanceX(); + } + + /** + * Returns debug information about this class. + */ + @Override + public String toString(){ + return new String(this.getClass().getName() + + "[name=" + this.name + //$NON-NLS-1$ + ",style="+ this.style + //$NON-NLS-1$ + ",fps=" + this.fontProperties + "]"); //$NON-NLS-1$ //$NON-NLS-2$ + } + + /** + * Returns Glyph object corresponding to the default glyph. + */ + @Override + public Glyph getDefaultGlyph(){ + // !! only first physical font used to get this value + return fPhysicalFonts[0].getDefaultGlyph(); + } + + /** + * Returns FontExtraMetrics object with extra metrics + * related to this CompositeFont. + */ + @Override + public FontExtraMetrics getExtraMetrics(){ + // Returns FontExtraMetrics instanse of the first physical + // Font from the array of fonts. + return fPhysicalFonts[0].getExtraMetrics(); + } + + /** + * Disposes CompositeFont object's resources. + */ + @Override + public void dispose() { + // Nothing to dispose + } +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/font/FontExtraMetrics.java b/app/src/main/java/org/apache/harmony/awt/gl/font/FontExtraMetrics.java new file mode 100644 index 000000000..047ba6d10 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/font/FontExtraMetrics.java @@ -0,0 +1,145 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + * + */ +package org.apache.harmony.awt.gl.font; + +/** + * Extra font metrics: sub/superscripts sizes, offsets, average char width. + */ +public class FontExtraMetrics { + + /* !! Subscript/superscript metrics are undefined for Type1. As a possible + * solution we can use values for Type1, that are proportionate to TrueType + * ones: + * SubscriptSizeX == 0.7 * fontSize + * SubscriptSizeY == 0.65 * fontSize + * SubscriptOffsetX == 0; + * SubscriptOffsetY == 0.15 * fontSize; + * SuperscriptSizeX == 0.7 * fontSize + * SuperscriptSizeY == 0.65 * fontSize + * SuperscriptOffsetX == 0; + * SuperscriptOffsetY == 0.45 * fontSize + * + */ + + /* + * The average width of characters in the font. + */ + private float lAverageCharWidth; + + /* + * Horizontal size for subscripts. + */ + private float lSubscriptSizeX; + + /* + * Vertical size for subscripts. + */ + private float lSubscriptSizeY; + + /* + * Horizontal offset for subscripts, the offset from the character origin + * to the origin of the subscript character. + */ + private float lSubscriptOffsetX; + + /* + * Vertical offset for subscripts, the offset from the character origin + * to the origin of the subscript character. + */ + private float lSubscriptOffsetY; + + /* + * Horizontal size for superscripts. + */ + private float lSuperscriptSizeX; + + /* + * Vertical size for superscripts. + */ + private float lSuperscriptSizeY; + + /* + * Horizontal offset for superscripts, the offset from the character + * base line to the base line of the superscript character. + */ + private float lSuperscriptOffsetX; + + /* + * Vertical offset for superscripts, the offset from the character + * base line to the base line of the superscript character. + */ + private float lSuperscriptOffsetY; + + public FontExtraMetrics(){ + // default constructor + } + + public FontExtraMetrics(float[] metrics){ + lAverageCharWidth = metrics[0]; + lSubscriptSizeX = metrics[1]; + lSubscriptSizeY = metrics[2]; + lSubscriptOffsetX = metrics[3]; + lSubscriptOffsetY = metrics[4]; + lSuperscriptSizeX = metrics[5]; + lSuperscriptSizeY = metrics[6]; + lSuperscriptOffsetX = metrics[7]; + lSuperscriptOffsetY = metrics[8]; + } + + public float getAverageCharWidth(){ + return lAverageCharWidth; + } + + public float getSubscriptSizeX(){ + return lSubscriptSizeX; + } + + public float getSubscriptSizeY(){ + return lSubscriptSizeY; + } + + public float getSubscriptOffsetX(){ + return lSubscriptOffsetX; + } + + public float getSubscriptOffsetY(){ + return lSubscriptOffsetY; + } + + public float getSuperscriptSizeX(){ + return lSuperscriptSizeX; + } + + public float getSuperscriptSizeY(){ + return lSuperscriptSizeY; + } + + public float getSuperscriptOffsetX(){ + return lSuperscriptOffsetX; + } + + public float getSuperscriptOffsetY(){ + return lSuperscriptOffsetY; + } + + +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/font/FontFinder.java b/app/src/main/java/org/apache/harmony/awt/gl/font/FontFinder.java new file mode 100644 index 000000000..09bcf5c96 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/font/FontFinder.java @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + * + * @date: Jul 12, 2005 + */ + +package org.apache.harmony.awt.gl.font; + +import java.awt.Font; +import java.awt.GraphicsEnvironment; +import java.util.List; +import java.util.Map; + +/** + * This class chooses the default font for the given text. + * If it finds the character which current font is unable to display + * it starts the next font run and looks for the font which is able to + * display the current character. It also caches the font mappings + * (index in the array containing all fonts) for the characters, + * using that fact that scripts are mainly contiguous in the UTF-16 encoding + * and there's a high probability that the upper byte will be the same for the + * next character as for the previous. This allows to save the space used for the cache. + */ +public class FontFinder { + private static final float DEFAULT_FONT_SIZE = 12; + + private static final Font fonts[] = + GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts(); + + private static final int NUM_BLOCKS = 256; + private static final int BLOCK_SIZE = 256; + private static final int INDEX_MASK = 0xFF; + private static final int BLOCK_SHIFT = 8; + + // Maps characters into the fonts array + private static final int blocks[][] = new int[NUM_BLOCKS][]; + + /** + * Finds the font which is able to display the given character + * and saves the font mapping for this character + * @param c - character + * @return font + */ + static Font findFontForChar(char c) { + int blockNum = c >> BLOCK_SHIFT; + int index = c & INDEX_MASK; + + if (blocks[blockNum] == null) { + blocks[blockNum] = new int[BLOCK_SIZE]; + } + + if (blocks[blockNum][index] == 0) { + blocks[blockNum][index] = 1; + + for (int i=0; i runStarts, + Map fonts) { + Font prevFont = null; + Font currFont; + for (int i = runStart; i < runLimit; i++) { + currFont = findFontForChar(text[i]); + if (currFont != prevFont) { + prevFont = currFont; + Integer idx = new Integer(i); + fonts.put(idx, currFont); + if (i != runStart) { + runStarts.add(idx); + } + } + } + } +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/font/FontManager.java b/app/src/main/java/org/apache/harmony/awt/gl/font/FontManager.java new file mode 100644 index 000000000..c1e327c98 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/font/FontManager.java @@ -0,0 +1,820 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ +package org.apache.harmony.awt.gl.font; + +import java.awt.Font; +import java.awt.peer.FontPeer; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.SoftReference; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Locale; +import java.util.Properties; +import java.util.Vector; + +import org.apache.harmony.awt.gl.CommonGraphics2DFactory; +import org.apache.harmony.luni.util.NotImplementedException; + + +public abstract class FontManager { + + //???AWT + boolean NOT_IMP = false; + + /** + * array of font families names + */ + public String[] allFamilies; + + public static final String DEFAULT_NAME = "Default"; /* Default font name */ //$NON-NLS-1$ + public static final String DIALOG_NAME = "Dialog"; /* Dialog font name */ //$NON-NLS-1$ + + /** + * Set of constants applicable to the TrueType 'name' table. + */ + public static final byte FAMILY_NAME_ID = 1; /* Family name identifier */ + public static final byte FONT_NAME_ID = 4; /* Full font name identifier */ + public static final byte POSTSCRIPT_NAME_ID = 6; /* PostScript name identifier */ + public static final short ENGLISH_LANGID = 0x0409; /* English (United States)language identifier */ + + /** + * Set of constants describing font type. + */ + public static final byte FONT_TYPE_TT = 4; /* TrueType type (TRUETYPE_FONTTYPE) */ + public static final byte FONT_TYPE_T1 = 2; /* Type1 type (DEVICE_FONTTYPE) */ + public static final byte FONT_TYPE_UNDEF = 0; /* Undefined type */ + + // logical family types (indices in FontManager.LOGICAL_FONT_NAMES) + static final int DIALOG = 3; // FF_SWISS + static final int SANSSERIF = 1; // FF_SWISS + static final int DIALOGINPUT = 4; // FF_MODERN + static final int MONOSPACED = 2; // FF_MODERN + static final int SERIF = 0; // FF_ROMAN + + + /** + * FontProperty related constants. + */ + public static final String PLATFORM_FONT_NAME = "PlatformFontName"; //$NON-NLS-1$ + public static final String LOGICAL_FONT_NAME = "LogicalFontName"; //$NON-NLS-1$ + public static final String COMPONENT_INDEX = "ComponentIndex"; //$NON-NLS-1$ + public static final String STYLE_INDEX = "StyleIndex"; //$NON-NLS-1$ + + public static final String[] FONT_MAPPING_KEYS = { + "LogicalFontName.StyleName.ComponentIndex", "LogicalFontName.ComponentIndex" //$NON-NLS-1$ //$NON-NLS-2$ + }; + + public static final String FONT_CHARACTER_ENCODING = "fontcharset.LogicalFontName.ComponentIndex"; //$NON-NLS-1$ + + public static final String EXCLUSION_RANGES = "exclusion.LogicalFontName.ComponentIndex"; //$NON-NLS-1$ + + public static final String FONT_FILE_NAME = "filename.PlatformFontName"; //$NON-NLS-1$ + + /** + * Available logical font families names. + */ + public static final String[] LOGICAL_FONT_FAMILIES = { + "Serif", "SansSerif", "Monospaced", "Dialog", "DialogInput" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ + }; + + /** + * Available logical font names. + */ + public static final String[] LOGICAL_FONT_NAMES = { + "serif", "serif.plain", "serif.bold", "serif.italic", "serif.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ + "sansserif", "sansserif.plain", "sansserif.bold", "sansserif.italic", "sansserif.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ + "monospaced", "monospaced.plain", "monospaced.bold", "monospaced.italic", "monospaced.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ + "dialog", "dialog.plain", "dialog.bold", "dialog.italic", "dialog.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ + "dialoginput", "dialoginput.plain", "dialoginput.bold", "dialoginput.italic", "dialoginput.bolditalic" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ + }; + + /** + * Available logical font face names. + */ + public static final String[] LOGICAL_FONT_FACES = { + "Serif", "Serif.plain", "Serif.bold", "Serif.italic", "Serif.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ + "Sansserif", "Sansserif.plain", "Sansserif.bold", "Sansserif.italic", "Sansserif.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ + "Monospaced", "Monospaced.plain", "Monospaced.bold", "Monospaced.italic", "Monospaced.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ + "Dialog", "Dialog.plain", "Dialog.bold", "Dialog.italic", "Dialog.bolditalic", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ + "Dialoginput", "Dialoginput.plain", "Dialoginput.bold", "Dialoginput.italic", "Dialoginput.bolditalic" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ + }; + + /** + * Set of font style names. + * Font.getStyle() corresponds to indexes in STYLE_NAMES array. + */ + public static final String[] STYLE_NAMES = { + "plain", "bold", "italic", "bolditalic" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + }; + + /** + * Logical font styles names table where font styles names used + * as the key and the value is the index of this style name. + */ + private static final Hashtable style_keys = new Hashtable(4); + + /** + * Initialize font styles keys table. + */ + static { + for (int i = 0; i < STYLE_NAMES.length; i++){ + style_keys.put(STYLE_NAMES[i], Integer.valueOf(i)); + } + } + + /** + * Return font style from the logical style name. + * + * @param lName style name of the logical face + */ + public static int getLogicalStyle(String lName){ + Integer value = style_keys.get(lName); + return value != null ? value.intValue(): -1; + } + + /** + * Set of possible "os" property values. + */ + public static final String[] OS_VALUES = { + "NT", "98", "2000", "Me", "XP", // For Windows //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ + "Redhat", "Turbo", "SuSE" // For Linux //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + }; + + /** + * Set of possible font.property file names. + * Language, Country, Encoding, OS, Version should be replaced with + * the values from current configuration. + */ + public static final String[] FP_FILE_NAMES = { + "/lib/font.properties.Language_Country_Encoding.OSVersion", //$NON-NLS-1$ + "/lib/font.properties.Language_Country_Encoding.OS", //$NON-NLS-1$ + "/lib/font.properties.Language_Country_Encoding.Version", //$NON-NLS-1$ + "/lib/font.properties.Language_Country_Encoding", //$NON-NLS-1$ + "/lib/font.properties.Language_Country.OSVersion", //$NON-NLS-1$ + "/lib/font.properties.Language_Country.OS", //$NON-NLS-1$ + "/lib/font.properties.Language_Country.Version", //$NON-NLS-1$ + "/lib/font.properties.Language_Country", //$NON-NLS-1$ + "/lib/font.properties.Language_Encoding.OSVersion", //$NON-NLS-1$ + "/lib/font.properties.Language_Encoding.OS", //$NON-NLS-1$ + "/lib/font.properties.Language_Encoding.Version", //$NON-NLS-1$ + "/lib/font.properties.Language_Encoding", //$NON-NLS-1$ + "/lib/font.properties.Language.OSVersion", //$NON-NLS-1$ + "/lib/font.properties.Language.OS", //$NON-NLS-1$ + "/lib/font.properties.Language.Version", //$NON-NLS-1$ + "/lib/font.properties.Language", //$NON-NLS-1$ + "/lib/font.properties.Encoding.OSVersion", //$NON-NLS-1$ + "/lib/font.properties.Encoding.OS", //$NON-NLS-1$ + "/lib/font.properties.Encoding.Version", //$NON-NLS-1$ + "/lib/font.properties.Encoding", //$NON-NLS-1$ + "/lib/font.properties.OSVersion", //$NON-NLS-1$ + "/lib/font.properties.OS", //$NON-NLS-1$ + "/lib/font.properties.Version", //$NON-NLS-1$ + "/lib/font.properties" //$NON-NLS-1$ + }; + + /** + * Table with all available font properties corresponding + * to the current system configuration. + */ + public Hashtable> fProperties = new Hashtable>(); + + public FontManager(){ + allFamilies = getAllFamilies(); + /* + * Creating and registering shutdown hook to free resources + * before object is destroyed. + */ + //???AWT + //DisposeNativeHook shutdownHook = new DisposeNativeHook(); + //Runtime.getRuntime().addShutdownHook(shutdownHook); + } + + /** + * Maximum number of unreferenced font peers to keep. + */ + public static final int EMPTY_FONTS_CAPACITY = 10; + + /** + * Locale - Language ID hash table. + */ + Hashtable tableLCID = new Hashtable(); + + /** + * Hash table that contains FontPeers instances. + */ + public Hashtable fontsTable = new Hashtable(); + + /** + * ReferenceQueue for HashMapReference objects to check + * if they were collected by garbage collector. + */ + public ReferenceQueue queue = new ReferenceQueue(); + + /** + * Singleton instance + */ + public final static FontManager inst = CommonGraphics2DFactory.inst.getFontManager(); + + /** + * Gets singleton instance of FontManager + * + * @return instance of FontManager implementation + */ + public static FontManager getInstance() { + return inst; + } + + /** + * Returns platform-dependent Font peer created from the specified + * Font object from the table with cached FontPeers instances. + * + * Note, this method checks whether FontPeer with specified parameters + * exists in the table with cached FontPeers' instances. If there is no needed + * instance - it is created and cached. + * + * @param fontName name of the font + * @param _fontStyle style of the font + * @param size font size + * + * @return platform dependent FontPeer implementation created from + * the specified parameters + */ + public FontPeer getFontPeer(String fontName, int _fontStyle, int size) { + updateFontsTable(); + + FontPeer peer = null; + String key; + String name; + int fontStyle = _fontStyle; + + int logicalIndex = getLogicalFaceIndex(fontName); + + if (logicalIndex != -1){ + name = getLogicalFaceFromFont(fontStyle, logicalIndex); + fontStyle = getStyleFromLogicalFace(name); + key = name.concat(String.valueOf(size)); + } else { + name = fontName; + key = name.concat(String.valueOf(fontStyle)). + concat(String.valueOf(size)); + } + + HashMapReference hmr = fontsTable.get(key); + if (hmr != null) { + peer = hmr.get(); + } + + if (peer == null) { + peer = createFontPeer(name, fontStyle, size, logicalIndex); + if (peer == null){ + peer = getFontPeer(DIALOG_NAME, fontStyle, size); + } + fontsTable.put(key, new HashMapReference(key, peer, queue)); + } + + return peer; + } + + /** + * Returns instance of font peer (logical or physical) according to the + * specified parameters. + * + * @param name font face name + * @param style style of the font + * @param size size of the font + * @param logicalIndex index of the logical face name in LOGICAL_FONT_FACES + * array or -1 if desired font peer is not logical. + */ + private FontPeer createFontPeer(String name, int style, int size, int logicalIndex){ + FontPeer peer; + if (logicalIndex != -1){ + peer = createLogicalFontPeer(name, style, size); + }else { + peer = createPhysicalFontPeer(name, style, size); + } + + return peer; + } + + /** + * Returns family name for logical face names as a parameter. + * + * @param faceName logical font face name + */ + public String getFamilyFromLogicalFace(String faceName){ + int pos = faceName.indexOf("."); //$NON-NLS-1$ + if (pos == -1){ + return faceName; + } + + return faceName.substring(0, pos); + } + + /** + * Returns new logical font peer for the parameters specified using font + * properties. + * + * @param faceName face name of the logical font + * @param style style of the font + * @param size font size + * + */ + private FontPeer createLogicalFontPeer(String faceName, int style, int size){ + String family = getFamilyFromLogicalFace(faceName); + FontProperty[] fps = getFontProperties(family.toLowerCase() + "." + style); //$NON-NLS-1$ + if (fps != null){ + int numFonts = fps.length; + FontPeerImpl[] physicalFonts = new FontPeerImpl[numFonts]; + for (int i = 0; i < numFonts; i++){ + FontProperty fp = fps[i]; + + String name = fp.getName(); + int fpStyle = fp.getStyle(); + String key = name.concat(String.valueOf(fpStyle)). + concat(String.valueOf(size)); + + HashMapReference hmr = fontsTable.get(key); + if (hmr != null) { + physicalFonts[i] = (FontPeerImpl)hmr.get(); + } + + if (physicalFonts[i] == null){ + physicalFonts[i] = (FontPeerImpl)createPhysicalFontPeer(name, fpStyle, size); + fontsTable.put(key, new HashMapReference(key, physicalFonts[i], queue)); + } + + if (physicalFonts[i] == null){ + physicalFonts[i] = (FontPeerImpl)getDefaultFont(style, size); + } + } + return new CompositeFont(family, faceName, style, size, fps, physicalFonts); + } + + // if there is no property for this logical font - default font is to be + // created + FontPeerImpl peer = (FontPeerImpl)getDefaultFont(style, size); + + return peer; + } + + /** + * Returns new physical font peer for the parameters specified using font properties + * This method must be overridden by subclasses implementations. + * + * @param faceName face name or family name of the font + * @param style style of the font + * @param size font size + * + */ + public abstract FontPeer createPhysicalFontPeer(String name, int style, int size); + + /** + * Returns default font peer class with "Default" name that is usually + * used when font with specified font names and style doesn't exsist + * on a system. + * + * @param style style of the font + * @param size size of the font + */ + public FontPeer getDefaultFont(int style, int size){ + updateFontsTable(); + + FontPeer peer = null; + String key = DEFAULT_NAME.concat(String.valueOf(style)). + concat(String.valueOf(size)); + + HashMapReference hmr = fontsTable.get(key); + if (hmr != null) { + peer = hmr.get(); + } + + if (peer == null) { + peer = createDefaultFont(style, size); + + ((FontPeerImpl)peer).setFamily(DEFAULT_NAME); + ((FontPeerImpl)peer).setPSName(DEFAULT_NAME); + ((FontPeerImpl)peer).setFontName(DEFAULT_NAME); + + fontsTable.put(key, new HashMapReference(key, peer, queue)); + } + + return peer; + } + + /** + * + * Returns new default font peer with "Default" name for the parameters + * specified. This method must be overridden by subclasses implementations. + * + * @param style style of the font + * @param size size of the font + */ + public abstract FontPeer createDefaultFont(int style, int size); + + /** + * Returns face name of the logical font, which is the result + * of specified font style and face style union. + * + * @param fontStyle specified style of the font + * @param logicalIndex index of the specified face from the + * LOGICAL_FONT_FACES array + * @return resulting face name + */ + public String getLogicalFaceFromFont(int fontStyle, int logicalIndex){ + int style = 0; + String name = LOGICAL_FONT_FACES[logicalIndex]; + int pos = name.indexOf("."); //$NON-NLS-1$ + + if (pos == -1){ + return createLogicalFace(name, fontStyle); + } + + String styleName = name.substring(pos+1); + name = name.substring(0, pos); + + // appending font style to the face style + style = fontStyle | getLogicalStyle(styleName); + + return createLogicalFace(name, style); + } + + /** + * Function returns style value from logical face name. + * + * @param name face name + * @return font style + */ + public int getStyleFromLogicalFace(String name){ + int style; + int pos = name.indexOf("."); //$NON-NLS-1$ + + if (pos == -1){ + return Font.PLAIN; + } + + String styleName = name.substring(pos+1); + + style = getLogicalStyle(styleName); + + return style; + } + + /** + * Returns logical face name corresponding to the logical + * family name and style of the font. + * + * @param family font family + * @param styleIndex index of the style name from the STYLE_NAMES array + */ + public String createLogicalFace(String family, int styleIndex){ + return family + "." + STYLE_NAMES[styleIndex]; //$NON-NLS-1$ + } + + /** + * Return language Id from LCID hash corresponding to the specified locale + * + * @param l specified locale + */ + public Short getLCID(Locale l){ + if (this.tableLCID.size() == 0){ + initLCIDTable(); + } + + return tableLCID.get(l.toString()); + } + + /** + * Platform-dependent LCID table init. + */ + public abstract void initLCIDTable(); + + /** + * Freeing native resources. This hook is used to avoid + * sudden application exit and to free resources created in native code. + */ + private class DisposeNativeHook extends Thread { + + @Override + public void run() { + try{ + /* Disposing native font peer's resources */ + Enumeration kEnum = fontsTable.keys(); + + while(kEnum.hasMoreElements()){ + Object key = kEnum.nextElement(); + HashMapReference hmr = fontsTable.remove(key); + FontPeerImpl delPeer = (FontPeerImpl)hmr.get(); + + if ((delPeer != null) && (delPeer.getClass() != CompositeFont.class)){ + // there's nothing to dispose in CompositeFont objects + delPeer.dispose(); + } + } + } catch (Throwable t){ + throw new RuntimeException(t); + } + } + } + + /** + * Returns File object, created in a directory + * according to the System, where JVM is being ran. + * + * In Linux case we use ".fonts" directory (for fontconfig purpose), + * where font file from the stream will be stored, hence in LinuxFontManager this + * method is overridden. + * In Windows case we use Windows temp directory (default implementation) + * + */ + public File getTempFontFile()throws IOException{ + //???AWT + /* + File fontFile = File.createTempFile("jFont", ".ttf"); //$NON-NLS-1$ //$NON-NLS-2$ + fontFile.deleteOnExit(); + + return fontFile; + */ + + if(NOT_IMP) + throw new NotImplementedException("getTempFontFile not Implemented"); + return null; + } + + /** + * Returns File object with font properties. It's name obtained using current + * system configuration properties and locale settings. If no appropriate + * file is found method returns null. + */ + public static File getFontPropertyFile(){ + File file = null; + + String javaHome = System.getProperty("java.home"); //$NON-NLS-1$ + Locale l = Locale.getDefault(); + String language = l.getLanguage(); + String country = l.getCountry(); + String fileEncoding = System.getProperty("file.encoding"); //$NON-NLS-1$ + + String os = System.getProperty("os.name"); //$NON-NLS-1$ + + int i = 0; + + // OS names from system properties don't match + // OS identifiers used in font.property files + for (; i < OS_VALUES.length; i++){ + if (os.endsWith(OS_VALUES[i])){ + os = OS_VALUES[i]; + break; + } + } + + if (i == OS_VALUES.length){ + os = null; + } + + String version = System.getProperty("os.version"); //$NON-NLS-1$ + String pathname; + + for (i = 0; i < FP_FILE_NAMES.length; i++){ + pathname = FP_FILE_NAMES[i]; + if (os != null){ + pathname = pathname.replaceFirst("OS", os); //$NON-NLS-1$ + } + + pathname = javaHome + pathname; + + pathname = pathname.replaceAll("Language", language). //$NON-NLS-1$ + replaceAll("Country", country). //$NON-NLS-1$ + replaceAll("Encoding", fileEncoding). //$NON-NLS-1$ + replaceAll("Version", version); //$NON-NLS-1$ + + file = new File(pathname); + + if (file.exists()){ + break; + } + } + + return file.exists() ? file : null; + } + + /** + * Returns an array of integer range values + * if the parameter exclusionString has format: + * Range + * Range [, exclusionString] + * + * Range: + * Char-Char + * + * Char: + * HexDigit HexDigit HexDigit HexDigit + * + * Method returns null if the specified string is null. + * + * @param exclusionString string parameter in specified format + */ + public static int[] parseIntervals(String exclusionString){ + int[] results = null; + + if (exclusionString == null){ + return null; + } + + String[] intervals = exclusionString.split(","); //$NON-NLS-1$ + + if (intervals != null){ + int num = intervals.length; + if (num > 0){ + results = new int[intervals.length << 1]; + for (int i = 0; i < intervals.length; i++){ + String ranges[] = intervals[i].split("-"); //$NON-NLS-1$ + results[i*2] = Integer.parseInt(ranges[0], 16); + results[i*2+1] = Integer.parseInt(ranges[1], 16); + + } + } + } + return results; + } + + /** + * Returns Properties from the properties file or null if + * there is an error with FileInputStream processing. + * + * @param file File object containing properties + */ + public static Properties getProperties(File file){ + Properties props = null; + FileInputStream fis = null; + try{ + fis = new FileInputStream(file); + props = new Properties(); + props.load(fis); + } catch (Exception e){ + System.out.println(e); + } + return props; + } + + /** + * Returns an array of FontProperties from the properties file + * with the specified property name "logical face.style". E.g. + * "dialog.2" corresponds to the font family Dialog with bold style. + * + * @param fpName key of the font properties in the properties set + */ + public FontProperty[] getFontProperties(String fpName){ + Vector props = fProperties.get(fpName); + + if (props == null){ + return null; + } + + int size = props.size(); + + if (size == 0){ + return null; + } + + FontProperty[] fps = new FontProperty[size]; + for (int i=0; i < fps.length; i++){ + fps[i] = props.elementAt(i); + } + return fps; + } + + /** + * Returns index of the font name in array of font names or -1 if + * this font is not logical. + * + * @param fontName specified font name + */ + public static int getLogicalFaceIndex(String fontName){ + for (int i=0; i { + + /** + * The key for Hashtable. + */ + private final String key; + + /** + * Creates a new soft reference with the key specified and + * adding this reference in the reference queue specified. + * + * @param key the key in Hashtable + * @param value object that corresponds to the key + * @param queue reference queue where reference is to be added + */ + public HashMapReference(final String key, final FontPeer value, + final ReferenceQueue queue) { + super(value, queue); + this.key = key; + } + + /** + * Returns the key that corresponds to the SoftReference instance + * + * @return the key in Hashtable with cached references + */ + public Object getKey() { + return key; + } + } + + /** + * Removes keys from the Hashtable with font peers which corresponding + * HashMapReference objects were garbage collected. + */ + private void updateFontsTable() { + HashMapReference r; + //???AWT + //while ((r = (HashMapReference)queue.poll()) != null) { + // fontsTable.remove(r.getKey()); + //} + } + +} + + diff --git a/app/src/main/java/org/apache/harmony/awt/gl/font/FontMetricsImpl.java b/app/src/main/java/org/apache/harmony/awt/gl/font/FontMetricsImpl.java new file mode 100644 index 000000000..778331787 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/font/FontMetricsImpl.java @@ -0,0 +1,282 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ +package org.apache.harmony.awt.gl.font; + +import com.android.internal.awt.AndroidGraphics2D; + +import java.awt.Font; +import java.awt.FontMetrics; +//import java.awt.Paint; +import java.awt.geom.AffineTransform; + +import android.graphics.Paint; + +/** + * FontMetrics implementation + */ + +public class FontMetricsImpl extends FontMetrics { + + private static final long serialVersionUID = 844695615201925138L; + + // ascent of the font + private int ascent; + + // descent of the font + private int descent; + + // leading of the font + private int leading; + + // maximum ascent of the font + private int maxAscent; + + // maximum descent of the font + private int maxDescent; + + // maximum advance of the font + private int maxAdvance; + + // array of char advance widths + private int[] widths = new int[256]; + + // font peer corresponding to this FontPeerImpl + private transient FontPeerImpl peer; + + // X scale parameter of the font transform + private float scaleX = 1; + + public AndroidGraphics2D mSg; + + private Font mFn; + + // Y scale parameter of the font transform + private float scaleY = 1; + + /** + * Creates new FontMericsImpl object described by the specified Font. + * + * @param fnt + * the specified Font object + */ + public FontMetricsImpl(Font fnt) { + super(fnt); + this.mFn = fnt; + + mSg = AndroidGraphics2D.getInstance(); + Paint p = mSg.getAndroidPaint(); + + this.ascent = (int)-p.ascent(); + this.descent = (int)p.descent(); + this.leading = p.getFontMetricsInt().leading; + + AffineTransform at = fnt.getTransform(); + if (!at.isIdentity()) { + scaleX = (float) at.getScaleX(); + scaleY = (float) at.getScaleY(); + } + + /* + * metrics[5] - strikethrough thickness

    + * -metrics[6] - strikethrough offset

    + * metrics[7] - maximum char width

    + * metrics[8] - ascent in pixels

    + * metrics[9] - descent in pixles

    + * metrics[10] - external leading in pixels

    + * metrics[11] - underline thickness in pixels

    + * -metrics[12] - underline offset in pixels

    + * metrics[13] - strikethrough thickness in pixels

    + * -metrics[14] - strikethrough offset in pixels

    + * metrics[15] - maximum char width in pixels

    + + * @param _baselineData an array of 3 elements with baseline offsets metrics

    + * _baselineData[0] - roman baseline offset

    + * _baselineData[1] - center baseline offset

    + * _baselineData[2] - hanging baseline offset

    + */ + } + + + /** + * Initialize the array of the first 256 chars' advance widths of the Font + * describing this FontMetricsImpl object. + */ + private void initWidths() { + + this.widths = new int[256]; + for (int chr = 0; chr < 256; chr++) { + widths[chr] = (int) (getFontPeer().charWidth((char) chr) * scaleX); + } + + } + + /** + * Returns the ascent of the Font describing this FontMetricsImpl object. + */ + @Override + public int getAscent() { + return this.ascent; + } + + /** + * Returns the descent of the Font describing this FontMetricsImpl object. + */ + @Override + public int getDescent() { + return this.descent; + } + + /** + * Returns the leading of the Font describing this FontMetricsImpl object. + */ + @Override + public int getLeading() { + return this.leading; + } + + /** + * Returns the advance width of the specified char of the Font describing + * this FontMetricsImpl object. + * + * @param ch + * the char which width is to be returned + * @return the advance width of the specified char of the Font describing + * this FontMetricsImpl object + */ + @Override + public int charWidth(int ch) { + if (ch < 256) { + return widths[ch]; + } + + return getFontPeer().charWidth((char) ch); + } + + /** + * Returns the advance width of the specified char of the Font describing + * this FontMetricsImpl object. + * + * @param ch + * the char which width is to be returned + * @return the advance width of the specified char of the Font describing + * this FontMetricsImpl object + */ + @Override + public int charWidth(char ch) { + if (ch < 256) { + return widths[ch]; + } + return (int) (getFontPeer().charWidth(ch) * scaleX); + } + + /** + * Returns the maximum advance of the Font describing this FontMetricsImpl + * object. + */ + @Override + public int getMaxAdvance() { + return this.maxAdvance; + } + + /** + * Returns the maximum ascent of the Font describing this FontMetricsImpl + * object. + */ + @Override + public int getMaxAscent() { + return this.maxAscent; + } + + /** + * Returns the maximum descent of the Font describing this FontMetricsImpl + * object. + */ + @SuppressWarnings("deprecation") + @Deprecated + @Override + public int getMaxDecent() { + return this.maxDescent; + } + + /** + * Returns the maximum descent of the Font describing this FontMetricsImpl + * object. + */ + @Override + public int getMaxDescent() { + return this.maxDescent; + } + + /** + * Returns the advance widths of the first 256 characters in the Font + * describing this FontMetricsImpl object. + */ + @Override + public int[] getWidths() { + return this.widths; + } + + /** + * Returns the total advance width of the specified string in the metrics of + * the Font describing this FontMetricsImpl object. + * + * @param str + * the String which width is to be measured + * @return the total advance width of the specified string in the metrics of + * the Font describing this FontMetricsImpl object + */ + @Override + public int stringWidth(String str) { + + int width = 0; + char chr; + + for (int i = 0; i < str.length(); i++) { + chr = str.charAt(i); + width += charWidth(chr); + } + return width; + + /* + * float res = 0; int ln = str.length(); char[] c = new char[ln]; float[] f = + * new float[ln]; str.getChars(0, ln, c, 0); mSg.getPaint().getTextWidths(c, 0, + * ln, f); + * + * for(int i = 0; i < f.length; i++) { res += f[i]; } return (int)res; + */ + } + + /** + * Returns FontPeer implementation of the Font describing this + * FontMetricsImpl object. + * + * @return a FontPeer object, that is the platform dependent FontPeer + * implementation for the Font describing this FontMetricsImpl + * object. + */ + @SuppressWarnings("deprecation") + public FontPeerImpl getFontPeer() { + if (peer == null) { + peer = (FontPeerImpl) font.getPeer(); + } + return peer; + } +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/font/FontPeerImpl.java b/app/src/main/java/org/apache/harmony/awt/gl/font/FontPeerImpl.java new file mode 100644 index 000000000..14ff99761 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/font/FontPeerImpl.java @@ -0,0 +1,499 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ +package org.apache.harmony.awt.gl.font; + + +import com.android.internal.awt.AndroidGraphics2D; +import com.android.internal.awt.AndroidGraphicsFactory; + +import java.awt.Graphics2D; +import java.awt.Toolkit; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.peer.FontPeer; + +import java.awt.font.FontRenderContext; +import java.awt.font.LineMetrics; +import java.util.ArrayList; +import java.util.Locale; + +import org.apache.harmony.awt.internal.nls.Messages; + +import android.graphics.Paint; + +/** + * Abstract class for platform dependent peer implementation of the Font class. + */ +public abstract class FontPeerImpl implements FontPeer{ + + // ascent of this font peer (in pixels) + int ascent; + + // descent of this font peer (in pixels) + int descent; + + // leading of this font peer (in pixels) + int leading; + + // logical maximum advance of this font peer (in pixels) + int maxAdvance; + + // the height of this font peer + float height; + + // the style of this font peer + int style; + + // the point size of this font peer (in pixels) + int size; + + // the logical hight of this font peer (in pixels) + int logicalHeight; + + // the name of this font peer + String name; + + // family name of this font peer + String fontFamilyName; + + // the Face name of this font peer + String faceName; + + // bounds rectanlge of the largest character in this font peer + Rectangle2D maxCharBounds; + + // italic angle value of this font peer + float italicAngle = 0.0f; + + // the number of glyphs supported by this font peer + int numGlyphs = 0; + + // native font handle + long pFont; + + // cached line metrics object + LineMetricsImpl nlm; + + // the postscript name of this font peer + String psName = null; + + /** + * Default glyph index, that is used, when the desired glyph + * is unsupported in this Font. + */ + public char defaultChar = (char)0xFFFF; + + /** + * Uniform LineMetrics flag, that is false for CompositeFont. + * Default value is true. + */ + boolean uniformLM = true; + + /** + * Flag of the type of this Font that is indicate is the Font + * has TrueType or Type1 type. Default value is FONT_TYPE_UNDEF. + */ + int fontType = FontManager.FONT_TYPE_UNDEF; + + /** + * Flag if this Font was created from stream, + * this parameter used in finilize method. + */ + private boolean createdFromStream = false; + + // temorary Font file name, if this FontPeerImpl was created from InputStream + private String tempFontFileName = null; + + // cached FontExtraMetrics object related to this font peer + FontExtraMetrics extraMetrix = null; + + public abstract FontExtraMetrics getExtraMetrics(); + + /** + * Returns LineMetrics object with specified parameters + * @param str specified String + * @param frc specified render context + * @param at specified affine transform + * @return + */ + public abstract LineMetrics getLineMetrics(String str, FontRenderContext frc, AffineTransform at); + + /** + * Returns postscript name of the font. + */ + public abstract String getPSName(); + + //private Graphics2D g = ((AndroidGraphicsFactory)Toolkit.getDefaultToolkit().getGraphicsFactory()).getGraphics2D(); + //private Graphics2D g = AndroidGraphics2D.getInstance(); + + /** + * Set postscript name of the font to the specified parameter. + */ + public void setPSName(String name){ + this.psName = name; + } + + /** + * Returns code of the missing glyph. + */ + public abstract int getMissingGlyphCode(); + + /** + * Returns Glyph representation of the given char. + * @param ch specified char + */ + public abstract Glyph getGlyph(char ch); + + /** + * Disposes nesessary resources. + */ + public abstract void dispose(); + + /** + * Returns Glyph represeting missing char. + */ + public abstract Glyph getDefaultGlyph(); + + /** + * Returns true if this FontPeerImpl can display the specified char + */ + public abstract boolean canDisplay(char c); + + /** + * Returns family name of the font in specified locale settings. + * @param l specified Locale + */ + public String getFamily(Locale l){ + return this.getFamily(); + } + + /** + * Sets family name of the font in specified locale settings. + */ + public void setFamily(String familyName){ + this.fontFamilyName = familyName; + } + + /** + * Returns face name of the font in specified locale settings. + * @param l specified Locale + */ + public String getFontName(Locale l){ + return this.getFontName(); + } + + /** + * Sets font name of the font in specified locale settings. + */ + public void setFontName(String fontName){ + this.faceName = fontName; + } + + /** + * Returns true, if this font peer was created from InputStream, false otherwise. + * In case of creating fonts from InputStream some font peer implementations + * may need to free temporary resources. + */ + public boolean isCreatedFromStream(){ + return this.createdFromStream; + } + + /** + * Sets createdFromStream flag to the specified parameter. + * If parameter is true it means font peer was created from InputStream. + * + * @param value true, if font peer was created from InputStream + */ + public void setCreatedFromStream(boolean value){ + this.createdFromStream = value; + } + + /** + * Returns font file name of this font. + */ + public String getTempFontFileName(){ + return this.tempFontFileName; + } + + /** + * Sets font file name of this font to the specified one. + * @param value String representing font file name + */ + public void setFontFileName(String value){ + this.tempFontFileName = value; + } + + /** + * Returns the advance width of the specified char of this FontPeerImpl. + * Note, if glyph is absent in the font's glyphset - returned value + * is the advance of the deafualt glyph. For escape-chars returned + * width value is 0. + * + * @param ch the char which width is to be returned + * @return the advance width of the specified char of this FontPeerImpl + */ + public int charWidth(char ch) { + Paint p; + AndroidGraphics2D g = AndroidGraphics2D.getInstance(); + if(g == null) { + throw new RuntimeException("AndroidGraphics2D not instantiated!"); + } + p = ((AndroidGraphics2D)g).getAndroidPaint(); + char[] ca = {ch}; + float[] fa = new float[1]; + p.getTextWidths(ca, 0, 1, fa); + return (int)fa[0]; + } + + /** + * Returns the advance width of the specified char of this FontPeerImpl. + * + * @param ind the char which width is to be returned + * @return the advance width of the specified char of this FontPeerImpl + */ + public int charWidth(int ind) { + return charWidth((char)ind); + } + + /** + * Returns an array of Glyphs that represent characters from the specified + * Unicode range. + * + * @param uFirst start position in Unicode range + * @param uLast end position in Unicode range + * @return + */ + public Glyph[] getGlyphs(char uFirst, char uLast) { + + char i = uFirst; + int len = uLast - uFirst; + ArrayList lst = new ArrayList(len); + + if (size < 0) { + // awt.09=min range bound value is greater than max range bound + throw new IllegalArgumentException(Messages.getString("awt.09")); //$NON-NLS-1$ + } + + while (i < uLast) { + lst.add(this.getGlyph(i)); + } + + return (Glyph[]) lst.toArray(); + } + + /** + * Returns an array of Glyphs representing given array of chars. + * + * @param chars specified array of chars + */ + public Glyph[] getGlyphs(char[] chars) { + if (chars == null){ + return null; + } + + Glyph[] result = new Glyph[chars.length]; + + for (int i = 0; i < chars.length; i++) { + result[i] = this.getGlyph(chars[i]); + } + return result; + } + + /** + * Returns an array of Glyphs representing given string. + * + * @param str specified string + */ + public Glyph[] getGlyphs(String str) { + char[] chars = str.toCharArray(); + return this.getGlyphs(chars); + } + + /** + * Returns family name of this FontPeerImpl. + */ + public String getFamily() { + return fontFamilyName; + } + + /** + * Returns face name of this FontPeerImpl. + */ + public String getFontName() { + if (this.fontType == FontManager.FONT_TYPE_T1){ + return this.fontFamilyName; + } + + return faceName; + } + + /** + * Returns height of this font peer in pixels. + */ + public int getLogicalHeight() { + return logicalHeight; + } + + /** + * Sets height of this font peer in pixels to the given value. + * + * @param newHeight new height in pixels value + */ + public void setLogicalHeight(int newHeight) { + logicalHeight = newHeight; + } + + /** + * Returns font size. + */ + public int getSize() { + return size; + } + + /** + * Returns font style. + */ + public int getStyle() { + return style; + } + + /** + * Returns font name. + */ + public String getName() { + return name; + } + + /** + * Returns the bounds of the largest char in this FontPeerImpl in + * specified render context. + * + * @param frc specified FontRenderContext + */ + public Rectangle2D getMaxCharBounds(FontRenderContext frc) { + return maxCharBounds; + } + + /** + * Returns the number of glyphs in this FontPeerImpl. + */ + public int getNumGlyphs() { + return numGlyphs; + } + + /** + * Returns tangens of the italic angle of this FontPeerImpl. + * If the FontPeerImpl has TrueType font type, italic angle value can be + * calculated as (CharSlopeRun / CharSlopeRise) in terms of GDI. + */ + public float getItalicAngle() { + return italicAngle; + } + + /** + * Returns height of this font peer. + */ + public float getHeight(){ + return height; + } + + /** + * Returns cached LineMetrics object of this font peer. + */ + public LineMetrics getLineMetrics(){ + return nlm; + } + + /** + * Returns native font handle of this font peer. + */ + public long getFontHandle(){ + return pFont; + } + + /** + * Returns ascent of this font peer. + */ + public int getAscent(){ + Paint p; + AndroidGraphics2D g = AndroidGraphics2D.getInstance(); + if(g == null) { + throw new RuntimeException("AndroidGraphics2D not instantiated!"); + } + p = ((AndroidGraphics2D)g).getAndroidPaint(); + return (int)p.ascent(); + //return ascent; + } + + /** + * Returns descent of this font peer. + */ + public int getDescent(){ + return descent; + } + + /** + * Returns leading of this font peer. + */ + public int getLeading(){ + return leading; + } + + /** + * Returns true if this font peer has uniform line metrics. + */ + public boolean hasUniformLineMetrics(){ + return uniformLM; + } + + /** + * Returns type of this font. + * + * @return one of constant font type values. + */ + public int getFontType(){ + return fontType; + } + + /** + * Sets new font type to the font object. + * + * @param newType new type value + */ + public void setFontType(int newType){ + if (newType == FontManager.FONT_TYPE_T1 || newType == FontManager.FONT_TYPE_TT){ + fontType = newType; + } + } + + /** + * Sets new font type to the font object. + * + * @param newType new type value + */ + @Override + protected void finalize() throws Throwable { + super.finalize(); + + dispose(); + } + +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/font/FontProperty.java b/app/src/main/java/org/apache/harmony/awt/gl/font/FontProperty.java new file mode 100644 index 000000000..4eb7cbb0d --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/font/FontProperty.java @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ + +package org.apache.harmony.awt.gl.font; + + +/** + * Class containing font property information. This information can be found + * in font.property files. See API documentation, logical fonts description part. + * + */ +public class FontProperty { + + // font file name + String fileName = null; + + // name of the encoding to be used + String encoding = null; + + // array of exclusion ranges (pairs of low and high unicode exclusion bounds) + int[] exclRange = null; + + // font face name + String name = null; + + // font style + int style = -1; + + /** + * Returns font style of this font property. + */ + public int getStyle(){ + return this.style; + } + + /** + * Returns font name of this font property. + */ + public String getName(){ + return this.name; + } + + /** + * Returns encoding used in this font property. + */ + public String getEncoding(){ + return this.encoding; + } + + /** + * Returns an array of exclusion ranges. This array contain pairs of + * low and high bounds of the intervals of characters to ignore in + * total Unicode characters range. + */ + public int[] getExclusionRange(){ + return this.exclRange; + } + + /** + * Returns file name of the font that is described by this font property. + */ + public String getFileName(){ + return this.fileName; + } + + /** + * Returns true if specified character covered by exclusion ranges of this + * font property, false otherwise. + * + * @param ch specified char to check + */ + public boolean isCharExcluded(char ch){ + if (exclRange == null ){ + return false; + } + + for (int i = 0; i < exclRange.length;){ + int lb = exclRange[i++]; + int hb = exclRange[i++]; + + if (ch >= lb && ch <= hb){ + return true; + } + } + + return false; + } +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/font/Glyph.java b/app/src/main/java/org/apache/harmony/awt/gl/font/Glyph.java new file mode 100644 index 000000000..44b8809d8 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/font/Glyph.java @@ -0,0 +1,236 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ +package org.apache.harmony.awt.gl.font; + +import java.awt.Shape; +import java.awt.font.GlyphJustificationInfo; +import java.awt.font.GlyphMetrics; +import java.awt.image.BufferedImage; + +public abstract class Glyph{ + + // character of the glyph + char glChar; + + // precise glyph metrics + GlyphMetrics glMetrics; + + // glyph metrics in pixels + GlyphMetrics glPointMetrics; + + // glyph code of this Glyph + int glCode; + + // justification info of this glyph + GlyphJustificationInfo glJustInfo; + + // native font handle of the font corresponding to this glyph + long pFont; + + // size of the font corresponding to this glyph + int fontSize; + + // bitmap representation of the glyph + byte[] bitmap = null; + + // Buffered image representation of the glyph + BufferedImage image; + + // shape that representing the outline of this glyph + Shape glOutline = null; + + /** + * image bitmap parameters + */ + + // top side bearing + public int bmp_top = 0; + + // left side bearing + public int bmp_left = 0; + + // number of bytes in row + public int bmp_pitch; + + // number of rows + public int bmp_rows; + + // width of the row + public int bmp_width; + + /** + * Retruns handle to Native Font object + */ + public long getPFont(){ + return this.pFont; + } + + /** + * Retruns char value of this glyph object + */ + public char getChar(){ + return glChar; + } + + /** + * Retruns precise width of this glyph object + */ + public int getWidth(){ + return Math.round((float)glMetrics.getBounds2D().getWidth()); + } + + /** + * Retruns precise height of this glyph object + */ + public int getHeight(){ + return Math.round((float)glMetrics.getBounds2D().getHeight()); + } + + /** + * Retruns glyph code of this glyph object + */ + public int getGlyphCode(){ + return glCode; + } + + /** + * Retruns GlyphMetrics of this glyph object with precise metrics. + */ + public GlyphMetrics getGlyphMetrics(){ + return glMetrics; + } + + /** + * Retruns GlyphMetrics of this glyph object in pixels. + */ + public GlyphMetrics getGlyphPointMetrics(){ + return glPointMetrics; + } + + /** + * Retruns GlyphJustificationInfo of this glyph object + */ + public GlyphJustificationInfo getGlyphJustificationInfo(){ + return glJustInfo; + } + + /** + * Sets JustificationInfo of this glyph object + * + * @param newJustInfo GlyphJustificationInfo object to set to the Glyph object + */ + public void setGlyphJustificationInfo(GlyphJustificationInfo newJustInfo){ + this.glJustInfo = newJustInfo; + } + + /** + * Returns an int array of 3 elements, so-called ABC structure that contains + * the width of the character: + * 1st element = left side bearing of the glyph + * 2nd element = width of the glyph + * 3d element = right side bearing of the glyph + */ + public int[] getABC(){ + int[] abc = new int[3]; + abc[0] = (int)glMetrics.getLSB(); + abc[1] = (int)glMetrics.getBounds2D().getWidth(); + abc[2] = (int)glMetrics.getRSB(); + + return abc; + } + + /** + * Sets BufferedImage representation of this glyph to the specified parameter. + * + * @param newImage new BufferedImage object to be set as BufferedImage + * representation. + */ + public void setImage(BufferedImage newImage){ + this.image = newImage; + } + + /** + * Returns true if this Glyph and specified object are equal. + */ + @Override + public boolean equals(Object obj){ + if (obj == this) { + return true; + } + + if (obj != null) { + try { + Glyph gl = (Glyph)obj; + + return ((this.getChar() == gl.getChar()) + && (this.getGlyphMetrics().equals(gl.getGlyphMetrics())) + && (this.getGlyphCode() == gl.getGlyphCode())); + } catch (ClassCastException e) { + } + } + + return false; + } + + /** + * Returns height of the glyph in points. + */ + public int getPointHeight(){ + return (int)glPointMetrics.getBounds2D().getHeight(); + } + + /** + * Returns width of the glyph in points. + */ + public int getPointWidth(){ + return (int)glPointMetrics.getBounds2D().getWidth(); + } + + public Shape getShape(){ + if (glOutline == null){ + glOutline = initOutline(this.glChar); + } + return glOutline; + } + + /** + * Sets BufferedImage representation of this glyph. + */ + public BufferedImage getImage(){ + //!! Implementation classes must override this method + return null; + } + + /** + * Returns array of bytes, representing image of this glyph + */ + public abstract byte[] getBitmap(); + + /** + * Returns shape that represents outline of the specified character. + * + * @param c specified character + */ + public abstract Shape initOutline(char c); + +} + + diff --git a/app/src/main/java/org/apache/harmony/awt/gl/font/LineMetricsImpl.java b/app/src/main/java/org/apache/harmony/awt/gl/font/LineMetricsImpl.java new file mode 100644 index 000000000..370146d91 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/font/LineMetricsImpl.java @@ -0,0 +1,412 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ +package org.apache.harmony.awt.gl.font; + +import java.awt.font.LineMetrics; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * + * LineMetrics implementation class. + */ + +public class LineMetricsImpl extends LineMetrics implements Cloneable{ + + // array of baseline offsets + float[] baselineOffsets; + + // the number of characters to measure + int numChars; + + // baseline index of the font corresponding to this line metrics + int baseLineIndex; + + // underline thickness + float underlineThickness; + + // underline offset + float underlineOffset; + + // strikethrough thickness + float strikethroughThickness; + + // strikethrough offset + float strikethroughOffset; + + // External leading + float leading; + + // Height of the font ( == (ascent+descent+leading)) + float height; + + // Ascent of the font + float ascent; + + // Descent of the font + float descent; + + // Width of the widest char in the font + float maxCharWidth; + + // underline thickness (in pixels) + int lUnderlineThickness; + + // underline offset (in pixels) + int lUnderlineOffset; + + // strikethrough thickness (in pixels) + int lStrikethroughThickness; + + // strikethrough offset (in pixels) + int lStrikethroughOffset; + + // External leading (in pixels) + int lLeading; + + // Height of the font ( == (ascent+descent+leading)) (in pixels) + int lHeight; + + // Ascent of the font (in pixels) + int lAscent; + + // Descent of the font (in pixels) + int lDescent; + + // Width of the widest char in the font (in pixels) + int lMaxCharWidth; + + // units per EM square in font value + int units_per_EM = 0; + + /** + * Creates LineMetricsImpl object from specified parameters. If baseline data parameter + * is null than {0, (-ascent+descent)/2, -ascent} values are used for baseline offsets. + * + * @param len a number of characters + * @param metrics an array of 16 elements with metrics values that can be + * initialized in native code.

    + * metrics[0] - ascent

    + * metrics[1] - descent

    + * metrics[2] - external leading

    + * metrics[3] - underline thickness

    + * -metrics[4] - underline offset

    + * metrics[5] - strikethrough thickness

    + * -metrics[6] - strikethrough offset

    + * metrics[7] - maximum char width

    + * metrics[8] - ascent in pixels

    + * metrics[9] - descent in pixles

    + * metrics[10] - external leading in pixels

    + * metrics[11] - underline thickness in pixels

    + * -metrics[12] - underline offset in pixels

    + * metrics[13] - strikethrough thickness in pixels

    + * -metrics[14] - strikethrough offset in pixels

    + * metrics[15] - maximum char width in pixels

    + + * @param _baselineData an array of 3 elements with baseline offsets metrics

    + * _baselineData[0] - roman baseline offset

    + * _baselineData[1] - center baseline offset

    + * _baselineData[2] - hanging baseline offset

    + */ + public LineMetricsImpl(int len, float[] metrics, float[] _baselineData){ + numChars = len; + + ascent = metrics[0]; // Ascent of the font + descent = metrics[1]; // Descent of the font + leading = metrics[2]; // External leading + height = metrics[0] + metrics[1] + metrics[2]; // Height of the font ( == (ascent + descent + leading)) + } + + /** + * Creates LineMetricsImpl object from specified parameters. If baseline data parameter + * is null than {0, (-ascent+descent)/2, -ascent} values are used for baseline offsets. + * + * @param _numChars number of chars + * @param _baseLineIndex index of the baseline offset + * @param _baselineOffsets an array of baseline offsets + * @param _underlineThickness underline thickness + * @param _underlineOffset underline offset + * @param _strikethroughThickness strikethrough thickness + * @param _strikethroughOffset strinkethrough offset + * @param _leading leading of the font + * @param _height font height + * @param _ascent ascent of the font + * @param _descent descent of the font + * @param _maxCharWidth max char width + */ + public LineMetricsImpl(int _numChars, int _baseLineIndex, + float[] _baselineOffsets, float _underlineThickness, + float _underlineOffset, float _strikethroughThickness, + float _strikethroughOffset, float _leading, float _height, + float _ascent, float _descent, float _maxCharWidth) { + + numChars = _numChars; + baseLineIndex = _baseLineIndex; + underlineThickness = _underlineThickness; + underlineOffset = _underlineOffset; + strikethroughThickness = _strikethroughThickness; + strikethroughOffset = _strikethroughOffset; + leading = _leading; + height = _height; + ascent = _ascent; + descent = _descent; + baselineOffsets = _baselineOffsets; + lUnderlineThickness = (int) underlineThickness; + lUnderlineOffset = (int) underlineOffset; + lStrikethroughThickness = (int) strikethroughThickness; + lStrikethroughOffset = (int) strikethroughOffset; + lLeading = (int) leading; + lHeight = (int) height; + lAscent = (int) ascent; + lDescent = (int) descent; + maxCharWidth = _maxCharWidth; + } + + public LineMetricsImpl(){ + + } + + /** + * All metrics are scaled according to scaleX and scaleY values. + * This function helps to recompute metrics according to the scale factors + * of desired AffineTransform. + * + * @param scaleX scale X factor + * @param scaleY scale Y factor + */ + public void scale(float scaleX, float scaleY){ + float absScaleX = Math.abs(scaleX); + float absScaleY = Math.abs(scaleY); + + underlineThickness *= absScaleY; + underlineOffset *= scaleY; + strikethroughThickness *= absScaleY; + strikethroughOffset *= scaleY; + leading *= absScaleY; + height *= absScaleY; + ascent *= absScaleY; + descent *= absScaleY; + + if(baselineOffsets == null) { + getBaselineOffsets(); + } + + for (int i=0; i< baselineOffsets.length; i++){ + baselineOffsets[i] *= scaleY; + } + + lUnderlineThickness *= absScaleY; + lUnderlineOffset *= scaleY; + lStrikethroughThickness *= absScaleY; + lStrikethroughOffset *= scaleY; + lLeading *= absScaleY; + lHeight *= absScaleY; + lAscent *= absScaleY; + lDescent *= absScaleY; + maxCharWidth *= absScaleX; + + } + + + /** + * Returns offset of the baseline. + */ + @Override + public float[] getBaselineOffsets() { + // XXX: at the moment there only horizontal metrics are taken into + // account. If there is no baseline information in TrueType font + // file default values used: {0, -ascent, (-ascent+descent)/2} + + return baselineOffsets; + } + + /** + * Returns a number of chars in specified text + */ + @Override + public int getNumChars() { + return numChars; + } + + /** + * Returns index of the baseline, one of predefined constants. + */ + @Override + public int getBaselineIndex() { + // Baseline index is the deafult baseline index value + // taken from the TrueType table "BASE". + return baseLineIndex; + } + + /** + * Returns thickness of the Underline. + */ + @Override + public float getUnderlineThickness() { + return underlineThickness; + } + + /** + * Returns offset of the Underline. + */ + @Override + public float getUnderlineOffset() { + return underlineOffset; + } + + /** + * Returns thickness of the Strikethrough line. + */ + @Override + public float getStrikethroughThickness() { + return strikethroughThickness; + } + + /** + * Returns offset of the Strikethrough line. + */ + @Override + public float getStrikethroughOffset() { + return strikethroughOffset; + } + + /** + * Returns the leading. + */ + @Override + public float getLeading() { + return leading; + } + + /** + * Returns the height of the font. + */ + @Override + public float getHeight() { + //return height; // equals to (ascent + descent + leading); + return ascent + descent + leading; + } + + /** + * Returns the descent. + */ + @Override + public float getDescent() { + return descent; + } + + /** + * Returns the ascent. + */ + @Override + public float getAscent() { + return ascent; + } + + /** + * Returns logical thickness of the Underline. + */ + public int getLogicalUnderlineThickness() { + return lUnderlineThickness; + } + + /** + * Returns logical offset of the Underline. + */ + public int getLogicalUnderlineOffset() { + return lUnderlineOffset; + } + + /** + * Returns logical thickness of the Strikethrough line. + */ + public int getLogicalStrikethroughThickness() { + return lStrikethroughThickness; + } + + /** + * Returns logical offset of the Strikethrough line. + */ + public int getLogicalStrikethroughOffset() { + return lStrikethroughOffset; + } + + /** + * Returns the logical leading. + */ + public int getLogicalLeading() { + return lLeading; + } + + /** + * Returns the logical height of the font. + */ + public int getLogicalHeight() { + return lHeight; // equals to (ascent + descent + leading); + } + + /** + * Returns the logical descent. + */ + public int getLogicalDescent() { + return lDescent; + } + + /** + * Returns the logical ascent. + */ + public int getLogicalAscent() { + return lAscent; + } + + /** + * Returns the logical size of the widest char. + */ + public int getLogicalMaxCharWidth() { + return lMaxCharWidth; + } + + /** + * Returns the size of the widest char. + */ + public float getMaxCharWidth() { + return maxCharWidth; + } + + /** + * Set num chars to the desired value. + * + * @param num specified number of chars + */ + public void setNumChars(int num){ + numChars = num; + } + + @Override + public Object clone(){ + try{ + return super.clone(); + }catch (CloneNotSupportedException e){ + return null; + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/org/apache/harmony/awt/gl/font/TextDecorator.java b/app/src/main/java/org/apache/harmony/awt/gl/font/TextDecorator.java new file mode 100644 index 000000000..81905fd60 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/font/TextDecorator.java @@ -0,0 +1,433 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @author Oleg V. Khaschansky + * @version $Revision$ + */ + +package org.apache.harmony.awt.gl.font; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Paint; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.font.TextAttribute; +import java.awt.geom.Area; +import java.awt.geom.Line2D; +import java.awt.geom.Rectangle2D; +import java.text.AttributedCharacterIterator.Attribute; +import java.util.Map; + +/** + * This class is responsible for rendering text decorations like + * underline, strikethrough, text with background, etc. + */ +public class TextDecorator { + private static final TextDecorator inst = new TextDecorator(); + private TextDecorator() {} + static TextDecorator getInstance() { + return inst; + } + + /** + * This class encapsulates a set of decoration attributes for a single text run. + */ + static class Decoration { + private static final BasicStroke UNDERLINE_LOW_ONE_PIXEL_STROKE = + new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10); + + private static final BasicStroke UNDERLINE_LOW_TWO_PIXEL_STROKE = + new BasicStroke(2, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10); + + private static final BasicStroke UNDERLINE_LOW_DOTTED_STROKE = + new BasicStroke( + 1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10, + new float[] { 1, 1 }, 0 + ); + + private static final BasicStroke UNDERLINE_LOW_DOTTED_STROKE2 = + new BasicStroke( + 1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10, + new float[] { 1, 1 }, 1 + ); + + private static final BasicStroke UNDERLINE_LOW_DASHED_STROKE = + new BasicStroke( + 1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10, + new float[] { 4, 4 }, 0 + ); + + boolean ulOn = false; // Have standard underline? + BasicStroke ulStroke; + + BasicStroke imUlStroke; // Stroke for INPUT_METHOD_UNDERLINE + BasicStroke imUlStroke2; // Specially for UNDERLINE_LOW_GRAY + + boolean strikeThrough; + BasicStroke strikeThroughStroke; + + boolean haveStrokes = false; // Strokes already created? + + boolean swapBfFg; + Paint bg; // background color + Paint fg; // foreground color + + Paint graphicsPaint; // Slot for saving current paint + + Decoration( + Integer imUl, + boolean swap, + boolean sth, + Paint bg, Paint fg, + boolean ulOn) { + + if (imUl != null) { + // Determine which stroke to use + if (imUl == TextAttribute.UNDERLINE_LOW_ONE_PIXEL) { + this.imUlStroke = Decoration.UNDERLINE_LOW_ONE_PIXEL_STROKE; + } else if (imUl == TextAttribute.UNDERLINE_LOW_TWO_PIXEL) { + this.imUlStroke = Decoration.UNDERLINE_LOW_TWO_PIXEL_STROKE; + } else if (imUl == TextAttribute.UNDERLINE_LOW_DOTTED) { + this.imUlStroke = Decoration.UNDERLINE_LOW_DOTTED_STROKE; + } else if (imUl == TextAttribute.UNDERLINE_LOW_GRAY) { + this.imUlStroke = Decoration.UNDERLINE_LOW_DOTTED_STROKE; + this.imUlStroke2 = Decoration.UNDERLINE_LOW_DOTTED_STROKE2; + } else if (imUl == TextAttribute.UNDERLINE_LOW_DASHED) { + this.imUlStroke = Decoration.UNDERLINE_LOW_DASHED_STROKE; + } + } + + this.ulOn = ulOn; // Has underline + this.swapBfFg = swap; + this.strikeThrough = sth; + this.bg = bg; + this.fg = fg; + } + + /** + * Creates strokes of proper width according to the info + * stored in the BasicMetrics + * @param metrics - basic metrics + */ + private void getStrokes(BasicMetrics metrics) { + if (!haveStrokes) { + if (strikeThrough) { + strikeThroughStroke = + new BasicStroke( + metrics.strikethroughThickness, + BasicStroke.CAP_BUTT, + BasicStroke.JOIN_MITER, + 10 + ); + } + + if (ulOn) { + ulStroke = + new BasicStroke( + metrics.underlineThickness, + BasicStroke.CAP_BUTT, + BasicStroke.JOIN_MITER, + 10 + ); + } + + haveStrokes = true; + } + } + } + + /** + * Creates Decoration object from the set of text attributes + * @param attributes - text attributes + * @return Decoration object + */ + static Decoration getDecoration(Map attributes) { + if (attributes == null) { + return null; // It is for plain text + } + + Object underline = attributes.get(TextAttribute.UNDERLINE); + boolean hasStandardUnderline = underline == TextAttribute.UNDERLINE_ON; + + Object imUnderline = attributes.get(TextAttribute.INPUT_METHOD_UNDERLINE); + Integer imUl = (Integer) imUnderline; + + boolean swapBgFg = + TextAttribute.SWAP_COLORS_ON.equals( + attributes.get(TextAttribute.SWAP_COLORS) + ); + + boolean strikeThrough = + TextAttribute.STRIKETHROUGH_ON.equals( + attributes.get(TextAttribute.STRIKETHROUGH) + ); + + Paint fg = (Paint) attributes.get(TextAttribute.FOREGROUND); + Paint bg = (Paint) attributes.get(TextAttribute.BACKGROUND); + + if ( + !hasStandardUnderline && + imUnderline == null && + fg == null && + bg == null && + !swapBgFg && + !strikeThrough + ) { + return null; + } + return new Decoration(imUl, swapBgFg, strikeThrough, bg, fg, hasStandardUnderline); + } + + /** + * Fills the background before drawing if needed. + * + * @param trs - text segment + * @param g2d - graphics to draw to + * @param xOffset - offset in X direction to the upper left corner of the + * layout from the origin of the graphics + * @param yOffset - offset in Y direction to the upper left corner of the + * layout from the origin of the graphics + */ + static void prepareGraphics( + TextRunSegment trs, Graphics2D g2d, + float xOffset, float yOffset + ) { + Decoration d = trs.decoration; + + if (d.fg == null && d.bg == null && d.swapBfFg == false) { + return; // Nothing to do + } + + d.graphicsPaint = g2d.getPaint(); + + if (d.fg == null) { + d.fg = d.graphicsPaint; + } + + if (d.swapBfFg) { + // Fill background area + g2d.setPaint(d.fg); + Rectangle2D bgArea = trs.getLogicalBounds(); + Rectangle2D toFill = + new Rectangle2D.Double( + bgArea.getX() + xOffset, + bgArea.getY() + yOffset, + bgArea.getWidth(), + bgArea.getHeight() + ); + g2d.fill(toFill); + + // Set foreground color + g2d.setPaint(d.bg == null ? Color.WHITE : d.bg); + } else { + if (d.bg != null) { // Fill background area + g2d.setPaint(d.bg); + Rectangle2D bgArea = trs.getLogicalBounds(); + Rectangle2D toFill = + new Rectangle2D.Double( + bgArea.getX() + xOffset, + bgArea.getY() + yOffset, + bgArea.getWidth(), + bgArea.getHeight() + ); + g2d.fill(toFill); + } + + // Set foreground color + g2d.setPaint(d.fg); + } + } + + /** + * Restores the original state of the graphics if needed + * @param d - decoration + * @param g2d - graphics + */ + static void restoreGraphics(Decoration d, Graphics2D g2d) { + if (d.fg == null && d.bg == null && d.swapBfFg == false) { + return; // Nothing to do + } + + g2d.setPaint(d.graphicsPaint); + } + + /** + * Renders the text decorations + * @param trs - text run segment + * @param g2d - graphics to render to + * @param xOffset - offset in X direction to the upper left corner + * of the layout from the origin of the graphics + * @param yOffset - offset in Y direction to the upper left corner + * of the layout from the origin of the graphics + */ + static void drawTextDecorations( + TextRunSegment trs, Graphics2D g2d, + float xOffset, float yOffset + ) { + Decoration d = trs.decoration; + + if (!d.ulOn && d.imUlStroke == null && !d.strikeThrough) { + return; // Nothing to do + } + + float left = xOffset + (float) trs.getLogicalBounds().getMinX(); + float right = xOffset + (float) trs.getLogicalBounds().getMaxX(); + + Stroke savedStroke = g2d.getStroke(); + + d.getStrokes(trs.metrics); + + if (d.strikeThrough) { + float y = trs.y + yOffset + trs.metrics.strikethroughOffset; + g2d.setStroke(d.strikeThroughStroke); + g2d.draw(new Line2D.Float(left, y, right, y)); + } + + if (d.ulOn) { + float y = trs.y + yOffset + trs.metrics.underlineOffset; + g2d.setStroke(d.ulStroke); + g2d.draw(new Line2D.Float(left, y, right, y)); + } + + if (d.imUlStroke != null) { + float y = trs.y + yOffset + trs.metrics.underlineOffset; + g2d.setStroke(d.imUlStroke); + g2d.draw(new Line2D.Float(left, y, right, y)); + if (d.imUlStroke2 != null) { + y++; + g2d.setStroke(d.imUlStroke2); + g2d.draw(new Line2D.Float(left, y, right, y)); + } + } + + g2d.setStroke(savedStroke); + } + + /** + * Extends the visual bounds of the text run segment to + * include text decorations. + * @param trs - text segment + * @param segmentBounds - bounds of the undecorated text + * @param d - decoration + * @return extended bounds + */ + static Rectangle2D extendVisualBounds( + TextRunSegment trs, + Rectangle2D segmentBounds, + Decoration d + ) { + if (d == null) { + return segmentBounds; + } + double minx = segmentBounds.getMinX(); + double miny = segmentBounds.getMinY(); + double maxx = segmentBounds.getMaxX(); + double maxy = segmentBounds.getMaxY(); + + Rectangle2D lb = trs.getLogicalBounds(); + + if (d.swapBfFg || d.bg != null) { + minx = Math.min(lb.getMinX() - trs.x, minx); + miny = Math.min(lb.getMinY() - trs.y, miny); + maxx = Math.max(lb.getMaxX() - trs.x, maxx); + maxy = Math.max(lb.getMaxY() - trs.y, maxy); + } + + if (d.ulOn || d.imUlStroke != null || d.strikeThrough) { + minx = Math.min(lb.getMinX() - trs.x, minx); + maxx = Math.max(lb.getMaxX() - trs.x, maxx); + + d.getStrokes(trs.metrics); + + if (d.ulStroke != null) { + maxy = Math.max( + maxy, + trs.metrics.underlineOffset + + d.ulStroke.getLineWidth() + ); + } + + if (d.imUlStroke != null) { + maxy = Math.max( + maxy, + trs.metrics.underlineOffset + + d.imUlStroke.getLineWidth() + + (d.imUlStroke2 == null ? 0 : d.imUlStroke2.getLineWidth()) + ); + } + } + + return new Rectangle2D.Double(minx, miny, maxx-minx, maxy-miny); + } + + /** + * Extends the outline of the text run segment to + * include text decorations. + * @param trs - text segment + * @param segmentOutline - outline of the undecorated text + * @param d - decoration + * @return extended outline + */ + static Shape extendOutline( + TextRunSegment trs, + Shape segmentOutline, + Decoration d + ) { + if (d == null || !d.ulOn && d.imUlStroke == null && !d.strikeThrough) { + return segmentOutline; // Nothing to do + } + + Area res = new Area(segmentOutline); + + float left = (float) trs.getLogicalBounds().getMinX() - trs.x; + float right = (float) trs.getLogicalBounds().getMaxX() - trs.x; + + d.getStrokes(trs.metrics); + + if (d.strikeThrough) { + float y = trs.metrics.strikethroughOffset; + res.add(new Area(d.strikeThroughStroke.createStrokedShape( + new Line2D.Float(left, y, right, y) + ))); + } + + if (d.ulOn) { + float y = trs.metrics.underlineOffset; + res.add(new Area(d.ulStroke.createStrokedShape( + new Line2D.Float(left, y, right, y) + ))); + } + + if (d.imUlStroke != null) { + float y = trs.metrics.underlineOffset; + res.add(new Area(d.imUlStroke.createStrokedShape( + new Line2D.Float(left, y, right, y) + ))); + + if (d.imUlStroke2 != null) { + y++; + res.add(new Area(d.imUlStroke2.createStrokedShape( + new Line2D.Float(left, y, right, y) + ))); + } + } + + return res; + } +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/font/TextMetricsCalculator.java b/app/src/main/java/org/apache/harmony/awt/gl/font/TextMetricsCalculator.java new file mode 100644 index 000000000..88170aad5 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/font/TextMetricsCalculator.java @@ -0,0 +1,209 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + * + */ + +package org.apache.harmony.awt.gl.font; + +import java.awt.font.LineMetrics; +import java.awt.font.GraphicAttribute; +import java.awt.Font; +import java.util.HashMap; +import java.util.ArrayList; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * This class operates with an arbitrary text string which can include + * any number of style, font and direction runs. It is responsible for computation + * of the text metrics, such as ascent, descent, leading and advance. Actually, + * each text run segment contains logic which allows it to compute its own metrics and + * responsibility of this class is to combine metrics for all segments included in the text, + * managed by the associated TextRunBreaker object. + */ +public class TextMetricsCalculator { + TextRunBreaker breaker; // Associated run breaker + + // Metrics + float ascent = 0; + float descent = 0; + float leading = 0; + float advance = 0; + + private float baselineOffsets[]; + int baselineIndex; + + public TextMetricsCalculator(TextRunBreaker breaker) { + this.breaker = breaker; + checkBaselines(); + } + + /** + * Returns either values cached by checkBaselines method or reasonable + * values for the TOP and BOTTOM alignments. + * @param baselineIndex - baseline index + * @return baseline offset + */ + float getBaselineOffset(int baselineIndex) { + if (baselineIndex >= 0) { + return baselineOffsets[baselineIndex]; + } else if (baselineIndex == GraphicAttribute.BOTTOM_ALIGNMENT) { + return descent; + } else if (baselineIndex == GraphicAttribute.TOP_ALIGNMENT) { + return -ascent; + } else { + // awt.3F=Invalid baseline index + throw new IllegalArgumentException(Messages.getString("awt.3F")); //$NON-NLS-1$ + } + } + + public float[] getBaselineOffsets() { + float ret[] = new float[baselineOffsets.length]; + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(baselineOffsets, 0, ret, 0, baselineOffsets.length); + return ret; + } + + /** + * Take baseline offsets from the first font or graphic attribute + * and normalizes them, than caches the results. + */ + public void checkBaselines() { + // Take baseline offsets of the first font and normalize them + HashMap fonts = breaker.fonts; + + Object val = fonts.get(new Integer(0)); + + if (val instanceof Font) { + Font firstFont = (Font) val; + LineMetrics lm = firstFont.getLineMetrics(breaker.text, 0, 1, breaker.frc); + baselineOffsets = lm.getBaselineOffsets(); + baselineIndex = lm.getBaselineIndex(); + } else if (val instanceof GraphicAttribute) { + // Get first graphic attribute and use it + GraphicAttribute ga = (GraphicAttribute) val; + + int align = ga.getAlignment(); + + if ( + align == GraphicAttribute.TOP_ALIGNMENT || + align == GraphicAttribute.BOTTOM_ALIGNMENT + ) { + baselineIndex = GraphicAttribute.ROMAN_BASELINE; + } else { + baselineIndex = align; + } + + baselineOffsets = new float[3]; + baselineOffsets[0] = 0; + baselineOffsets[1] = (ga.getDescent() - ga.getAscent()) / 2.f; + baselineOffsets[2] = -ga.getAscent(); + } else { // Use defaults - Roman baseline and zero offsets + baselineIndex = GraphicAttribute.ROMAN_BASELINE; + baselineOffsets = new float[3]; + } + + // Normalize offsets if needed + if (baselineOffsets[baselineIndex] != 0) { + float baseOffset = baselineOffsets[baselineIndex]; + for (int i = 0; i < baselineOffsets.length; i++) { + baselineOffsets[i] -= baseOffset; + } + } + } + + /** + * Computes metrics for the text managed by the associated TextRunBreaker + */ + void computeMetrics() { + + ArrayList segments = breaker.runSegments; + + float maxHeight = 0; + float maxHeightLeading = 0; + + for (int i = 0; i < segments.size(); i++) { + TextRunSegment segment = segments.get(i); + BasicMetrics metrics = segment.metrics; + int baseline = metrics.baseLineIndex; + + if (baseline >= 0) { + float baselineOffset = baselineOffsets[metrics.baseLineIndex]; + float fixedDescent = metrics.descent + baselineOffset; + + ascent = Math.max(ascent, metrics.ascent - baselineOffset); + descent = Math.max(descent, fixedDescent); + leading = Math.max(leading, fixedDescent + metrics.leading); + } else { // Position is not fixed by the baseline, need sum of ascent and descent + float height = metrics.ascent + metrics.descent; + + maxHeight = Math.max(maxHeight, height); + maxHeightLeading = Math.max(maxHeightLeading, height + metrics.leading); + } + } + + // Need to increase sizes for graphics? + if (maxHeightLeading != 0) { + descent = Math.max(descent, maxHeight - ascent); + leading = Math.max(leading, maxHeightLeading - ascent); + } + + // Normalize leading + leading -= descent; + + BasicMetrics currMetrics; + float currAdvance = 0; + + for (int i = 0; i < segments.size(); i++) { + TextRunSegment segment = segments.get(breaker.getSegmentFromVisualOrder(i)); + currMetrics = segment.metrics; + + segment.y = getBaselineOffset(currMetrics.baseLineIndex) + + currMetrics.superScriptOffset; + segment.x = currAdvance; + + currAdvance += segment.getAdvance(); + } + + advance = currAdvance; + } + + /** + * Computes metrics and creates BasicMetrics object from them + * @return basic metrics + */ + public BasicMetrics createMetrics() { + computeMetrics(); + return new BasicMetrics(this); + } + + /** + * Corrects advance after justification. Gets BasicMetrics object + * and updates advance stored into it. + * @param metrics - metrics with outdated advance which should be corrected + */ + public void correctAdvance(BasicMetrics metrics) { + ArrayList segments = breaker.runSegments; + TextRunSegment segment = segments.get(breaker + .getSegmentFromVisualOrder(segments.size() - 1)); + + advance = segment.x + segment.getAdvance(); + metrics.advance = advance; + } +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/font/TextRunBreaker.java b/app/src/main/java/org/apache/harmony/awt/gl/font/TextRunBreaker.java new file mode 100644 index 000000000..8e831bf3e --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/font/TextRunBreaker.java @@ -0,0 +1,861 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + * + */ + +package org.apache.harmony.awt.gl.font; + + +import java.awt.geom.GeneralPath; +import java.awt.geom.Rectangle2D; +import java.awt.im.InputMethodHighlight; +import java.awt.font.*; +import java.awt.*; +import java.text.AttributedCharacterIterator; +import java.text.Annotation; +import java.text.AttributedCharacterIterator.Attribute; +import java.util.*; + +import org.apache.harmony.awt.gl.font.TextDecorator.Decoration; +import org.apache.harmony.awt.internal.nls.Messages; +import org.apache.harmony.misc.HashCode; +// TODO - bidi not implemented yet + +/** + * This class is responsible for breaking the text into the run segments + * with constant font, style, other text attributes and direction. + * It also stores the created text run segments and covers functionality + * related to the operations on the set of segments, like calculating metrics, + * rendering, justification, hit testing, etc. + */ +public class TextRunBreaker implements Cloneable { + AttributedCharacterIterator aci; + FontRenderContext frc; + + char[] text; + + byte[] levels; + + HashMap fonts; + HashMap decorations; + + // Related to default font substitution + int forcedFontRunStarts[]; + + ArrayList runSegments = new ArrayList(); + + // For fast retrieving of the segment containing + // character with known logical index + int logical2segment[]; + int segment2visual[]; // Visual order of segments TODO - implement + int visual2segment[]; + int logical2visual[]; + int visual2logical[]; + + SegmentsInfo storedSegments; + private boolean haveAllSegments = false; + int segmentsStart, segmentsEnd; + + float justification = 1.0f; + + public TextRunBreaker(AttributedCharacterIterator aci, FontRenderContext frc) { + this.aci = aci; + this.frc = frc; + + segmentsStart = aci.getBeginIndex(); + segmentsEnd = aci.getEndIndex(); + + int len = segmentsEnd - segmentsStart; + text = new char[len]; + aci.setIndex(segmentsEnd); + while (len-- != 0) { // Going in backward direction is faster? Simplier checks here? + text[len] = aci.previous(); + } + + createStyleRuns(); + } + + /** + * Visual order of text segments may differ from the logical order. + * This method calculates visual position of the segment from its logical position. + * @param segmentNum - logical position of the segment + * @return visual position of the segment + */ + int getVisualFromSegmentOrder(int segmentNum) { + return (segment2visual == null) ? segmentNum : segment2visual[segmentNum]; + } + + /** + * Visual order of text segments may differ from the logical order. + * This method calculates logical position of the segment from its visual position. + * @param visual - visual position of the segment + * @return logical position of the segment + */ + int getSegmentFromVisualOrder(int visual) { + return (visual2segment == null) ? visual : visual2segment[visual]; + } + + /** + * Visual order of the characters may differ from the logical order. + * This method calculates visual position of the character from its logical position. + * @param logical - logical position of the character + * @return visual position + */ + int getVisualFromLogical(int logical) { + return (logical2visual == null) ? logical : logical2visual[logical]; + } + + /** + * Visual order of the characters may differ from the logical order. + * This method calculates logical position of the character from its visual position. + * @param visual - visual position + * @return logical position + */ + int getLogicalFromVisual(int visual) { + return (visual2logical == null) ? visual : visual2logical[visual]; + } + + /** + * Calculates the end index of the level run, limited by the given text run. + * @param runStart - run start + * @param runEnd - run end + * @return end index of the level run + */ + int getLevelRunLimit(int runStart, int runEnd) { + if (levels == null) { + return runEnd; + } + int endLevelRun = runStart + 1; + byte level = levels[runStart]; + + while (endLevelRun <= runEnd && levels[endLevelRun] == level) { + endLevelRun++; + } + + return endLevelRun; + } + + /** + * Adds InputMethodHighlight to the attributes + * @param attrs - text attributes + * @return patched text attributes + */ + Map unpackAttributes(Map attrs) { + if (attrs.containsKey(TextAttribute.INPUT_METHOD_HIGHLIGHT)) { + Map styles = null; + + Object val = attrs.get(TextAttribute.INPUT_METHOD_HIGHLIGHT); + + if (val instanceof Annotation) { + val = ((Annotation) val).getValue(); + } + + if (val instanceof InputMethodHighlight) { + InputMethodHighlight ihl = ((InputMethodHighlight) val); + styles = ihl.getStyle(); + + if (styles == null) { + Toolkit tk = Toolkit.getDefaultToolkit(); + styles = tk.mapInputMethodHighlight(ihl); + } + } + + if (styles != null) { + HashMap newAttrs = new HashMap(); + newAttrs.putAll(attrs); + newAttrs.putAll(styles); + return newAttrs; + } + } + + return attrs; + } + + /** + * Breaks the text into separate style runs. + */ + void createStyleRuns() { + // TODO - implement fast and simple case + fonts = new HashMap(); + decorations = new HashMap(); + //// + + ArrayList forcedFontRunStartsList = null; + + Map attributes = null; + + // Check justification attribute + Object val = aci.getAttribute(TextAttribute.JUSTIFICATION); + if (val != null) { + justification = ((Float) val).floatValue(); + } + + for ( + int index = segmentsStart, nextRunStart = segmentsStart; + index < segmentsEnd; + index = nextRunStart, aci.setIndex(index) + ) { + nextRunStart = aci.getRunLimit(); + attributes = unpackAttributes(aci.getAttributes()); + + TextDecorator.Decoration d = TextDecorator.getDecoration(attributes); + decorations.put(new Integer(index), d); + + // Find appropriate font or place GraphicAttribute there + + // 1. Try to pick up CHAR_REPLACEMENT (compatibility) + Font value = (Font)attributes.get(TextAttribute.CHAR_REPLACEMENT); + + if (value == null) { + // 2. Try to Get FONT + value = (Font)attributes.get(TextAttribute.FONT); + + if (value == null) { + // 3. Try to create font from FAMILY + if (attributes.get(TextAttribute.FAMILY) != null) { + value = Font.getFont(attributes); + } + + if (value == null) { + // 4. No attributes found, using default. + if (forcedFontRunStartsList == null) { + forcedFontRunStartsList = new ArrayList(); + } + FontFinder.findFonts( + text, + index, + nextRunStart, + forcedFontRunStartsList, + fonts + ); + value = fonts.get(new Integer(index)); + } + } + } + + fonts.put(new Integer(index), value); + } + + // We have added some default fonts, so we have some extra runs in text + if (forcedFontRunStartsList != null) { + forcedFontRunStarts = new int[forcedFontRunStartsList.size()]; + for (int i=0; i runStart) { + maxPos = Math.min(element, maxPos); + break; + } + } + } + + return Math.min(aci.getRunLimit(), maxPos); + } + + /** + * Creates segments for the text run with + * constant decoration, font and bidi level + * @param runStart - run start + * @param runEnd - run end + */ + public void createSegments(int runStart, int runEnd) { + int endStyleRun, endLevelRun; + + // TODO - update levels + + int pos = runStart, levelPos; + + aci.setIndex(pos); + final int firstRunStart = aci.getRunStart(); + Object tdd = decorations.get(new Integer(firstRunStart)); + Object fontOrGAttr = fonts.get(new Integer(firstRunStart)); + + logical2segment = new int[runEnd - runStart]; + + do { + endStyleRun = getStyleRunLimit(pos, runEnd); + + // runStart can be non-zero, but all arrays will be indexed from 0 + int ajustedPos = pos - runStart; + int ajustedEndStyleRun = endStyleRun - runStart; + levelPos = ajustedPos; + do { + endLevelRun = getLevelRunLimit(levelPos, ajustedEndStyleRun); + + if (fontOrGAttr instanceof GraphicAttribute) { + runSegments.add( + new TextRunSegmentImpl.TextRunSegmentGraphic( + (GraphicAttribute)fontOrGAttr, + endLevelRun - levelPos, + levelPos + runStart) + ); + Arrays.fill(logical2segment, levelPos, endLevelRun, runSegments.size()-1); + } else { + TextRunSegmentImpl.TextSegmentInfo i = + new TextRunSegmentImpl.TextSegmentInfo( + levels == null ? 0 : levels[ajustedPos], + (Font) fontOrGAttr, + frc, + text, + levelPos + runStart, + endLevelRun + runStart + ); + + runSegments.add( + new TextRunSegmentImpl.TextRunSegmentCommon( + i, + (TextDecorator.Decoration) tdd + ) + ); + Arrays.fill(logical2segment, levelPos, endLevelRun, runSegments.size()-1); + } + + levelPos = endLevelRun; + } while (levelPos < ajustedEndStyleRun); + + // Prepare next iteration + pos = endStyleRun; + tdd = decorations.get(new Integer(pos)); + fontOrGAttr = fonts.get(new Integer(pos)); + } while (pos < runEnd); + } + + /** + * Checks if text run segments are up to date and creates the new segments if not. + */ + public void createAllSegments() { + if ( !haveAllSegments && + (logical2segment == null || + logical2segment.length != segmentsEnd - segmentsStart) + ) { // Check if we don't have all segments yet + resetSegments(); + createSegments(segmentsStart, segmentsEnd); + } + + haveAllSegments = true; + } + + /** + * Calculates position where line should be broken without + * taking into account word boundaries. + * @param start - start index + * @param maxAdvance - maximum advance, width of the line + * @return position where to break + */ + public int getLineBreakIndex(int start, float maxAdvance) { + int breakIndex; + TextRunSegment s = null; + + for ( + int segmentIndex = logical2segment[start]; + segmentIndex < runSegments.size(); + segmentIndex++ + ) { + s = runSegments.get(segmentIndex); + breakIndex = s.getCharIndexFromAdvance(maxAdvance, start); + + if (breakIndex < s.getEnd()) { + return breakIndex; + } + maxAdvance -= s.getAdvanceDelta(start, s.getEnd()); + start = s.getEnd(); + } + + return s.getEnd(); + } + + /** + * Inserts character into the managed text. + * @param newParagraph - new character iterator + * @param insertPos - insertion position + */ + public void insertChar(AttributedCharacterIterator newParagraph, int insertPos) { + aci = newParagraph; + + char insChar = aci.setIndex(insertPos); + + Integer key = new Integer(insertPos); + + insertPos -= aci.getBeginIndex(); + + char newText[] = new char[text.length + 1]; + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(text, 0, newText, 0, insertPos); + newText[insertPos] = insChar; + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(text, insertPos, newText, insertPos+1, text.length - insertPos); + text = newText; + + if (aci.getRunStart() == key.intValue() && aci.getRunLimit() == key.intValue() + 1) { + createStyleRuns(); // We have to create one new run, could be optimized + } else { + shiftStyleRuns(key, 1); + } + + resetSegments(); + + segmentsEnd++; + } + + /** + * Deletes character from the managed text. + * @param newParagraph - new character iterator + * @param deletePos - deletion position + */ + public void deleteChar(AttributedCharacterIterator newParagraph, int deletePos) { + aci = newParagraph; + + Integer key = new Integer(deletePos); + + deletePos -= aci.getBeginIndex(); + + char newText[] = new char[text.length - 1]; + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(text, 0, newText, 0, deletePos); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(text, deletePos+1, newText, deletePos, newText.length - deletePos); + text = newText; + + if (fonts.get(key) != null) { + fonts.remove(key); + } + + shiftStyleRuns(key, -1); + + resetSegments(); + + segmentsEnd--; + } + + /** + * Shift all runs after specified position, needed to perfom insertion + * or deletion in the managed text + * @param pos - position where to start + * @param shift - shift, could be negative + */ + private void shiftStyleRuns(Integer pos, final int shift) { + ArrayList keys = new ArrayList(); + + Integer key, oldkey; + for (Iterator it = fonts.keySet().iterator(); it.hasNext(); ) { + oldkey = it.next(); + if (oldkey.intValue() > pos.intValue()) { + keys.add(oldkey); + } + } + + for (int i=0; i(); + logical2segment = null; + segment2visual = null; + visual2segment = null; + levels = null; + haveAllSegments = false; + } + + private class SegmentsInfo { + ArrayList runSegments; + int logical2segment[]; + int segment2visual[]; + int visual2segment[]; + byte levels[]; + int segmentsStart; + int segmentsEnd; + } + + /** + * Saves the internal state of the class + * @param newSegStart - new start index in the text + * @param newSegEnd - new end index in the text + */ + public void pushSegments(int newSegStart, int newSegEnd) { + storedSegments = new SegmentsInfo(); + storedSegments.runSegments = this.runSegments; + storedSegments.logical2segment = this.logical2segment; + storedSegments.segment2visual = this.segment2visual; + storedSegments.visual2segment = this.visual2segment; + storedSegments.levels = this.levels; + storedSegments.segmentsStart = segmentsStart; + storedSegments.segmentsEnd = segmentsEnd; + + resetSegments(); + + segmentsStart = newSegStart; + segmentsEnd = newSegEnd; + } + + /** + * Restores the internal state of the class + */ + public void popSegments() { + if (storedSegments == null) { + return; + } + + this.runSegments = storedSegments.runSegments; + this.logical2segment = storedSegments.logical2segment; + this.segment2visual = storedSegments.segment2visual; + this.visual2segment = storedSegments.visual2segment; + this.levels = storedSegments.levels; + this.segmentsStart = storedSegments.segmentsStart; + this.segmentsEnd = storedSegments.segmentsEnd; + storedSegments = null; + + if (runSegments.size() == 0 && logical2segment == null) { + haveAllSegments = false; + } else { + haveAllSegments = true; + } + } + + @Override + public Object clone() { + try { + TextRunBreaker res = (TextRunBreaker) super.clone(); + res.storedSegments = null; + ArrayList newSegments = new ArrayList(runSegments.size()); + for (int i = 0; i < runSegments.size(); i++) { + TextRunSegment seg = runSegments.get(i); + newSegments.add((TextRunSegment)seg.clone()); + } + res.runSegments = newSegments; + return res; + } catch (CloneNotSupportedException e) { + // awt.3E=Clone not supported + throw new UnsupportedOperationException(Messages.getString("awt.3E")); //$NON-NLS-1$ + } + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof TextRunBreaker)) { + return false; + } + + TextRunBreaker br = (TextRunBreaker) obj; + + if (br.getACI().equals(aci) && br.frc.equals(frc)) { + return true; + } + + return false; + } + + @Override + public int hashCode() { + return HashCode.combine(aci.hashCode(), frc.hashCode()); + } + + /** + * Renders the managed text + * @param g2d - graphics where to render + * @param xOffset - offset in X direction to the upper left corner + * of the layout from the origin of the graphics + * @param yOffset - offset in Y direction to the upper left corner + * of the layout from the origin of the graphics + */ + public void drawSegments(Graphics2D g2d, float xOffset, float yOffset) { + for (int i=0; i= x) || // We are in the segment + (endOfPrevSeg < x && bounds.getMinX() > x)) { // We are somewhere between the segments + return segment.hitTest(x,y); + } + endOfPrevSeg = bounds.getMaxX(); + } + + return isLTR() ? TextHitInfo.trailing(text.length) : TextHitInfo.leading(0); + } + + public float getJustification() { + return justification; + } + + /** + * Calculates position of the last non whitespace character + * in the managed text. + * @return position of the last non whitespace character + */ + public int getLastNonWhitespace() { + int lastNonWhitespace = text.length; + + while (lastNonWhitespace >= 0) { + lastNonWhitespace--; + if (!Character.isWhitespace(text[lastNonWhitespace])) { + break; + } + } + + return lastNonWhitespace; + } + + /** + * Performs justification of the managed text by changing segment positions + * and positions of the glyphs inside of the segments. + * @param gap - amount of space which should be compensated by justification + */ + public void justify(float gap) { + // Ignore trailing logical whitespace + int firstIdx = segmentsStart; + int lastIdx = getLastNonWhitespace() + segmentsStart; + JustificationInfo jInfos[] = new JustificationInfo[5]; + float gapLeft = gap; + + int highestPriority = -1; + // GlyphJustificationInfo.PRIORITY_KASHIDA is 0 + // GlyphJustificationInfo.PRIORITY_NONE is 3 + for (int priority = 0; priority <= GlyphJustificationInfo.PRIORITY_NONE + 1; priority++) { + JustificationInfo jInfo = new JustificationInfo(); + jInfo.lastIdx = lastIdx; + jInfo.firstIdx = firstIdx; + jInfo.grow = gap > 0; + jInfo.gapToFill = gapLeft; + + if (priority <= GlyphJustificationInfo.PRIORITY_NONE) { + jInfo.priority = priority; + } else { + jInfo.priority = highestPriority; // Last pass + } + + for (int i = 0; i < runSegments.size(); i++) { + TextRunSegment segment = runSegments.get(i); + if (segment.getStart() <= lastIdx) { + segment.updateJustificationInfo(jInfo); + } + } + + if (jInfo.priority == highestPriority) { + jInfo.absorb = true; + jInfo.absorbedWeight = jInfo.weight; + } + + if (jInfo.weight != 0) { + if (highestPriority < 0) { + highestPriority = priority; + } + jInfos[priority] = jInfo; + } else { + continue; + } + + gapLeft -= jInfo.growLimit; + + if (((gapLeft > 0) ^ jInfo.grow) || gapLeft == 0) { + gapLeft = 0; + jInfo.gapPerUnit = jInfo.gapToFill/jInfo.weight; + break; + } + jInfo.useLimits = true; + + if (jInfo.absorbedWeight > 0) { + jInfo.absorb = true; + jInfo.absorbedGapPerUnit = + (jInfo.gapToFill-jInfo.growLimit)/jInfo.absorbedWeight; + break; + } + } + + float currJustificationOffset = 0; + for (int i = 0; i < runSegments.size(); i++) { + TextRunSegment segment = + runSegments.get(getSegmentFromVisualOrder(i)); + segment.x += currJustificationOffset; + currJustificationOffset += segment.doJustification(jInfos); + } + + justification = -1; // Make further justification impossible + } + + /** + * This class represents the information collected before the actual + * justification is started and needed to perform the justification. + * This information is closely related to the information stored in the + * GlyphJustificationInfo for the text represented by glyph vectors. + */ + class JustificationInfo { + boolean grow; + boolean absorb = false; + boolean useLimits = false; + int priority = 0; + float weight = 0; + float absorbedWeight = 0; + float growLimit = 0; + + int lastIdx; + int firstIdx; + + float gapToFill; + + float gapPerUnit = 0; // Precalculated value, gapToFill / weight + float absorbedGapPerUnit = 0; // Precalculated value, gapToFill / weight + } +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/font/TextRunSegment.java b/app/src/main/java/org/apache/harmony/awt/gl/font/TextRunSegment.java new file mode 100644 index 000000000..1cd2c055a --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/font/TextRunSegment.java @@ -0,0 +1,165 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @author Oleg V. Khaschansky + * @version $Revision$ + */ + +package org.apache.harmony.awt.gl.font; + +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.font.TextHitInfo; +import java.awt.geom.Rectangle2D; + +/** + * Abstract class which represents the segment of the text with constant attributes + * running in one direction (i.e. constant level). + */ +public abstract class TextRunSegment implements Cloneable { + float x; // Calculated x location of this segment on the screen + float y; // Calculated y location of this segment on the screen + + BasicMetrics metrics; // Metrics of this text run segment + TextDecorator.Decoration decoration; // Underline, srikethrough, etc. + Rectangle2D logicalBounds = null; // Logical bounding box for the segment + Rectangle2D visualBounds = null; // Visual bounding box for the segment + + /** + * Returns start index of the segment + * @return start index + */ + abstract int getStart(); + + /** + * Returns end index of the segment + * @return end index + */ + abstract int getEnd(); + + /** + * Returns the number of characters in the segment + * @return number of characters + */ + abstract int getLength(); + + /** + * Renders this text run segment + * @param g2d - graphics to render to + * @param xOffset - X offset from the graphics origin to the + * origin of the text layout + * @param yOffset - Y offset from the graphics origin to the + * origin of the text layout + */ + abstract void draw(Graphics2D g2d, float xOffset, float yOffset); + + /** + * Creates black box bounds shape for the specified range + * @param start - range sart + * @param limit - range end + * @return black box bounds shape + */ + abstract Shape getCharsBlackBoxBounds(int start, int limit); + + /** + * Returns the outline shape + * @return outline + */ + abstract Shape getOutline(); + + /** + * Returns visual bounds of this segment + * @return visual bounds + */ + abstract Rectangle2D getVisualBounds(); + + /** + * Returns logical bounds of this segment + * @return logical bounds + */ + abstract Rectangle2D getLogicalBounds(); + + /** + * Calculates advance of the segment + * @return advance + */ + abstract float getAdvance(); + + /** + * Calculates advance delta between two characters + * @param start - 1st position + * @param end - 2nd position + * @return advance increment between specified positions + */ + abstract float getAdvanceDelta(int start, int end); + + /** + * Calculates index of the character which advance is equal to + * the given. If the given advance is greater then the segment + * advance it returns the position after the last character. + * @param advance - given advance + * @param start - character, from which to start measuring advance + * @return character index + */ + abstract int getCharIndexFromAdvance(float advance, int start); + + /** + * Checks if the character doesn't contribute to the text advance + * @param index - character index + * @return true if the character has zero advance + */ + abstract boolean charHasZeroAdvance(int index); + + /** + * Calculates position of the character on the screen + * @param index - character index + * @return X coordinate of the character position + */ + abstract float getCharPosition(int index); + + /** + * Returns the advance of the individual character + * @param index - character index + * @return character advance + */ + abstract float getCharAdvance(int index); + + /** + * Creates text hit info from the hit position + * @param x - X coordinate relative to the origin of the layout + * @param y - Y coordinate relative to the origin of the layout + * @return hit info + */ + abstract TextHitInfo hitTest(float x, float y); + + /** + * Collects justification information into JustificationInfo object + * @param jInfo - JustificationInfo object + */ + abstract void updateJustificationInfo(TextRunBreaker.JustificationInfo jInfo); + + /** + * Performs justification of the segment. + * Updates positions of individual characters. + * @param jInfos - justification information, gathered by the previous passes + * @return amount of growth or shrink of the segment + */ + abstract float doJustification(TextRunBreaker.JustificationInfo jInfos[]); + + @Override + public abstract Object clone(); +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/font/TextRunSegmentImpl.java b/app/src/main/java/org/apache/harmony/awt/gl/font/TextRunSegmentImpl.java new file mode 100644 index 000000000..0ec2d05da --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/font/TextRunSegmentImpl.java @@ -0,0 +1,979 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + * + */ + +package org.apache.harmony.awt.gl.font; + +import java.awt.*; +import java.awt.font.*; +import java.awt.geom.Rectangle2D; +import java.awt.geom.GeneralPath; +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +// XXX - TODO - bidi not implemented yet +//import java.text.Bidi; +import java.util.Arrays; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * Date: Apr 25, 2005 + * Time: 4:33:18 PM + * + * This class contains the implementation of the behavior of the + * text run segment with constant text attributes and direction. + */ +public class TextRunSegmentImpl { + + /** + * This class contains basic information required for creation + * of the glyph-based text run segment. + */ + public static class TextSegmentInfo { + // XXX - TODO - bidi not implemented yet + //Bidi bidi; + + Font font; + FontRenderContext frc; + + char text[]; + + int start; + int end; + int length; + + int flags = 0; + + byte level = 0; + + TextSegmentInfo( + byte level, + Font font, FontRenderContext frc, + char text[], int start, int end + ) { + this.font = font; + this.frc = frc; + this.text = text; + this.start = start; + this.end = end; + this.level = level; + length = end - start; + } + } + + /** + * This class represents a simple text segment backed by the glyph vector + */ + public static class TextRunSegmentCommon extends TextRunSegment { + TextSegmentInfo info; + private GlyphVector gv; + private float advanceIncrements[]; + private int char2glyph[]; + private GlyphJustificationInfo gjis[]; // Glyph justification info + + TextRunSegmentCommon(TextSegmentInfo i, TextDecorator.Decoration d) { + // XXX - todo - check support bidi + i.flags &= ~0x09; // Clear bidi flags + + if ((i.level & 0x1) != 0) { + i.flags |= Font.LAYOUT_RIGHT_TO_LEFT; + } + + info = i; + this.decoration = d; + + LineMetrics lm = i.font.getLineMetrics(i.text, i.start, i.end, i.frc); + this.metrics = new BasicMetrics(lm, i.font); + + if (lm.getNumChars() != i.length) { // XXX todo - This should be handled + // awt.41=Font returned unsupported type of line metrics. This case is known, but not supported yet. + throw new UnsupportedOperationException( + Messages.getString("awt.41")); //$NON-NLS-1$ + } + } + + @Override + public Object clone() { + return new TextRunSegmentCommon(info, decoration); + } + + /** + * Creates glyph vector from the managed text if needed + * @return glyph vector + */ + private GlyphVector getGlyphVector() { + if (gv==null) { + gv = info.font.layoutGlyphVector( + info.frc, + info.text, + info.start, + info.end - info.start, // NOTE: This parameter violates + // spec, it is count, + // not limit as spec states + info.flags + ); + } + + return gv; + } + + /** + * Renders this text run segment + * @param g2d - graphics to render to + * @param xOffset - X offset from the graphics origin to the + * origin of the text layout + * @param yOffset - Y offset from the graphics origin to the + * origin of the text layout + */ + @Override + void draw(Graphics2D g2d, float xOffset, float yOffset) { + if (decoration == null) { + g2d.drawGlyphVector(getGlyphVector(), xOffset + x, yOffset + y); + } else { + TextDecorator.prepareGraphics(this, g2d, xOffset, yOffset); + g2d.drawGlyphVector(getGlyphVector(), xOffset + x, yOffset + y); + TextDecorator.drawTextDecorations(this, g2d, xOffset, yOffset); + TextDecorator.restoreGraphics(decoration, g2d); + } + } + + /** + * Returns visual bounds of this segment + * @return visual bounds + */ + @Override + Rectangle2D getVisualBounds() { + if (visualBounds == null) { + visualBounds = + TextDecorator.extendVisualBounds( + this, + getGlyphVector().getVisualBounds(), + decoration + ); + + visualBounds.setRect( + x + visualBounds.getX(), + y + visualBounds.getY(), + visualBounds.getWidth(), + visualBounds.getHeight() + ); + } + + return (Rectangle2D) visualBounds.clone(); + } + + /** + * Returns logical bounds of this segment + * @return logical bounds + */ + @Override + Rectangle2D getLogicalBounds() { + if (logicalBounds == null) { + logicalBounds = getGlyphVector().getLogicalBounds(); + + logicalBounds.setRect( + x + logicalBounds.getX(), + y + logicalBounds.getY(), + logicalBounds.getWidth(), + logicalBounds.getHeight() + ); + } + + return (Rectangle2D) logicalBounds.clone(); + } + + @Override + float getAdvance() { + return (float) getLogicalBounds().getWidth(); + } + + /** + * Attemts to map each character to the corresponding advance increment + */ + void initAdvanceMapping() { + GlyphVector gv = getGlyphVector(); + int charIndicies[] = gv.getGlyphCharIndices(0, gv.getNumGlyphs(), null); + advanceIncrements = new float[info.length]; + + for (int i=0; i info.length) { + end = info.length; + } + + float sum = 0; + for (int i=start; i info.length) { + limit = info.length; + } + + GeneralPath result = new GeneralPath(); + + int glyphIndex = 0; + + for (int i=start; i info.length) { + index = info.length; + } + + float result = 0; + + int glyphIndex = getChar2Glyph()[index]; + result = (float) getGlyphVector().getGlyphPosition(glyphIndex).getX(); + + // Shift to the segment's coordinates + result += x; + + return result; + } + + /** + * Returns the advance of the individual character + * @param index - character index + * @return character advance + */ + @Override + float getCharAdvance(int index) { + if (advanceIncrements == null) { + initAdvanceMapping(); + } + + return advanceIncrements[index - this.getStart()]; + } + + /** + * Returns the outline shape + * @return outline + */ + @Override + Shape getOutline() { + AffineTransform t = AffineTransform.getTranslateInstance(x, y); + return t.createTransformedShape( + TextDecorator.extendOutline( + this, + getGlyphVector().getOutline(), + decoration + ) + ); + } + + /** + * Checks if the character doesn't contribute to the text advance + * @param index - character index + * @return true if the character has zero advance + */ + @Override + boolean charHasZeroAdvance(int index) { + if (advanceIncrements == null) { + initAdvanceMapping(); + } + + return advanceIncrements[index - this.getStart()] == 0; + } + + /** + * Creates text hit info from the hit position + * @param hitX - X coordinate relative to the origin of the layout + * @param hitY - Y coordinate relative to the origin of the layout + * @return hit info + */ + @Override + TextHitInfo hitTest(float hitX, float hitY) { + hitX -= x; + + float glyphPositions[] = + getGlyphVector().getGlyphPositions(0, info.length+1, null); + + int glyphIdx; + boolean leading = false; + for (glyphIdx = 1; glyphIdx <= info.length; glyphIdx++) { + if (glyphPositions[(glyphIdx)*2] >= hitX) { + float advance = + glyphPositions[(glyphIdx)*2] - glyphPositions[(glyphIdx-1)*2]; + leading = glyphPositions[(glyphIdx-1)*2] + advance/2 > hitX ? true : false; + glyphIdx--; + break; + } + } + + if (glyphIdx == info.length) { + glyphIdx--; + } + + int charIdx = getGlyphVector().getGlyphCharIndex(glyphIdx); + + return (leading) ^ ((info.level & 0x1) == 0x1)? + TextHitInfo.leading(charIdx + info.start) : + TextHitInfo.trailing(charIdx + info.start); + } + + /** + * Collects GlyphJustificationInfo objects from the glyph vector + * @return array of all GlyphJustificationInfo objects + */ + private GlyphJustificationInfo[] getGlyphJustificationInfos() { + if (gjis == null) { + GlyphVector gv = getGlyphVector(); + int nGlyphs = gv.getNumGlyphs(); + int charIndicies[] = gv.getGlyphCharIndices(0, nGlyphs, null); + gjis = new GlyphJustificationInfo[nGlyphs]; + + // Patch: temporary patch, getGlyphJustificationInfo is not implemented + float fontSize = info.font.getSize2D(); + GlyphJustificationInfo defaultInfo = + new GlyphJustificationInfo( + 0, // weight + false, GlyphJustificationInfo.PRIORITY_NONE, 0, 0, // grow + false, GlyphJustificationInfo.PRIORITY_NONE, 0, 0); // shrink + GlyphJustificationInfo spaceInfo = new GlyphJustificationInfo( + fontSize, // weight + true, GlyphJustificationInfo.PRIORITY_WHITESPACE, 0, fontSize, // grow + true, GlyphJustificationInfo.PRIORITY_WHITESPACE, 0, fontSize); // shrink + + //////// + // Temporary patch, getGlyphJustificationInfo is not implemented + for (int i = 0; i < nGlyphs; i++) { + //gjis[i] = getGlyphVector().getGlyphJustificationInfo(i); + + char c = info.text[charIndicies[i] + info.start]; + if (Character.isWhitespace(c)) { + gjis[i] = spaceInfo; + } else { + gjis[i] = defaultInfo; + } + // End patch + } + } + + return gjis; + } + + /** + * Collects justification information into JustificationInfo object + * @param jInfo - JustificationInfo object + */ + @Override + void updateJustificationInfo(TextRunBreaker.JustificationInfo jInfo) { + int lastChar = Math.min(jInfo.lastIdx, info.end) - info.start; + boolean haveFirst = info.start <= jInfo.firstIdx; + boolean haveLast = info.end >= (jInfo.lastIdx + 1); + + int prevGlyphIdx = -1; + int currGlyphIdx; + + if (jInfo.grow) { // Check how much we can grow/shrink on current priority level + for (int i=0; i 0 ? jInfos[lastPriority] : null; + + boolean haveFirst = info.start <= firstInfo.firstIdx; + boolean haveLast = info.end >= (firstInfo.lastIdx + 1); + + // Here we suppose that GLYPHS are ordered LEFT TO RIGHT + int firstGlyph = haveFirst ? + getChar2Glyph()[firstInfo.firstIdx - info.start] : + getChar2Glyph()[0]; + + int lastGlyph = haveLast ? + getChar2Glyph()[firstInfo.lastIdx - info.start] : + getChar2Glyph()[info.length - 1]; + if (haveLast) { + lastGlyph--; + } + + TextRunBreaker.JustificationInfo currInfo; + float glyphOffset = 0; + float positionIncrement = 0; + float sideIncrement = 0; + + if (haveFirst) { // Don't add padding before first char + GlyphJustificationInfo gji = getGlyphJustificationInfos()[firstGlyph]; + currInfo = jInfos[gji.growPriority]; + if (currInfo != null) { + if (currInfo.useLimits) { + if (currInfo.absorb) { + glyphOffset += gji.weight * currInfo.absorbedGapPerUnit; + } else if ( + lastInfo != null && + lastInfo.priority == currInfo.priority + ) { + glyphOffset += gji.weight * lastInfo.absorbedGapPerUnit; + } + glyphOffset += + firstInfo.grow ? + gji.growRightLimit : + -gji.shrinkRightLimit; + } else { + glyphOffset += gji.weight * currInfo.gapPerUnit; + } + } + + firstGlyph++; + } + + if (firstInfo.grow) { + for (int i=firstGlyph; i<=lastGlyph; i++) { + GlyphJustificationInfo gji = getGlyphJustificationInfos()[i]; + currInfo = jInfos[gji.growPriority]; + if (currInfo == null) { + // We still have to increment glyph position + Point2D glyphPos = getGlyphVector().getGlyphPosition(i); + glyphPos.setLocation(glyphPos.getX() + glyphOffset, glyphPos.getY()); + getGlyphVector().setGlyphPosition(i, glyphPos); + + continue; + } + + if (currInfo.useLimits) { + glyphOffset += gji.growLeftLimit; + if (currInfo.absorb) { + sideIncrement = gji.weight * currInfo.absorbedGapPerUnit; + glyphOffset += sideIncrement; + positionIncrement = glyphOffset; + glyphOffset += sideIncrement; + } else if (lastInfo != null && lastInfo.priority == currInfo.priority) { + sideIncrement = gji.weight * lastInfo.absorbedGapPerUnit; + glyphOffset += sideIncrement; + positionIncrement = glyphOffset; + glyphOffset += sideIncrement; + } else { + positionIncrement = glyphOffset; + } + glyphOffset += gji.growRightLimit; + } else { + sideIncrement = gji.weight * currInfo.gapPerUnit; + glyphOffset += sideIncrement; + positionIncrement = glyphOffset; + glyphOffset += sideIncrement; + } + + Point2D glyphPos = getGlyphVector().getGlyphPosition(i); + glyphPos.setLocation(glyphPos.getX() + positionIncrement, glyphPos.getY()); + getGlyphVector().setGlyphPosition(i, glyphPos); + } + } else { + for (int i=firstGlyph; i<=lastGlyph; i++) { + GlyphJustificationInfo gji = getGlyphJustificationInfos()[i]; + currInfo = jInfos[gji.shrinkPriority]; + if (currInfo == null) { + // We still have to increment glyph position + Point2D glyphPos = getGlyphVector().getGlyphPosition(i); + glyphPos.setLocation(glyphPos.getX() + glyphOffset, glyphPos.getY()); + getGlyphVector().setGlyphPosition(i, glyphPos); + + continue; + } + + if (currInfo.useLimits) { + glyphOffset -= gji.shrinkLeftLimit; + if (currInfo.absorb) { + sideIncrement = gji.weight * currInfo.absorbedGapPerUnit; + glyphOffset += sideIncrement; + positionIncrement = glyphOffset; + glyphOffset += sideIncrement; + } else if (lastInfo != null && lastInfo.priority == currInfo.priority) { + sideIncrement = gji.weight * lastInfo.absorbedGapPerUnit; + glyphOffset += sideIncrement; + positionIncrement = glyphOffset; + glyphOffset += sideIncrement; + } else { + positionIncrement = glyphOffset; + } + glyphOffset -= gji.shrinkRightLimit; + } else { + sideIncrement = gji.weight * currInfo.gapPerUnit; + glyphOffset += sideIncrement; + positionIncrement = glyphOffset; + glyphOffset += sideIncrement; + } + + Point2D glyphPos = getGlyphVector().getGlyphPosition(i); + glyphPos.setLocation(glyphPos.getX() + positionIncrement, glyphPos.getY()); + getGlyphVector().setGlyphPosition(i, glyphPos); + } + } + + + if (haveLast) { // Don't add padding after last char + lastGlyph++; + + GlyphJustificationInfo gji = getGlyphJustificationInfos()[lastGlyph]; + currInfo = jInfos[gji.growPriority]; + + if (currInfo != null) { + if (currInfo.useLimits) { + glyphOffset += firstInfo.grow ? gji.growLeftLimit : -gji.shrinkLeftLimit; + if (currInfo.absorb) { + glyphOffset += gji.weight * currInfo.absorbedGapPerUnit; + } else if (lastInfo != null && lastInfo.priority == currInfo.priority) { + glyphOffset += gji.weight * lastInfo.absorbedGapPerUnit; + } + } else { + glyphOffset += gji.weight * currInfo.gapPerUnit; + } + } + + // Ajust positions of all glyphs after last glyph + for (int i=lastGlyph; i length) { + return length + this.start; + } + return charOffset + start + this.start; + } + + @Override + int getStart() { + return start; + } + + @Override + int getEnd() { + return start + length; + } + + @Override + int getLength() { + return length; + } + + @Override + Shape getCharsBlackBoxBounds(int start, int limit) { + start -= this.start; + limit -= this.start; + + if (limit > length) { + limit = length; + } + + Rectangle2D charBounds = ga.getBounds(); + charBounds.setRect( + charBounds.getX() + ga.getAdvance() * start + x, + charBounds.getY() + y, + charBounds.getWidth() + ga.getAdvance() * (limit - start), + charBounds.getHeight() + ); + + return charBounds; + } + + @Override + float getCharPosition(int index) { + index -= start; + if (index > length) { + index = length; + } + + return ga.getAdvance() * index + x; + } + + @Override + float getCharAdvance(int index) { + return ga.getAdvance(); + } + + @Override + Shape getOutline() { + AffineTransform t = AffineTransform.getTranslateInstance(x, y); + return t.createTransformedShape( + TextDecorator.extendOutline(this, getVisualBounds(), decoration) + ); + } + + @Override + boolean charHasZeroAdvance(int index) { + return false; + } + + @Override + TextHitInfo hitTest(float hitX, float hitY) { + hitX -= x; + + float tmp = hitX / ga.getAdvance(); + int hitIndex = Math.round(tmp); + + if (tmp > hitIndex) { + return TextHitInfo.leading(hitIndex + this.start); + } + return TextHitInfo.trailing(hitIndex + this.start); + } + + @Override + void updateJustificationInfo(TextRunBreaker.JustificationInfo jInfo) { + // Do nothing + } + + @Override + float doJustification(TextRunBreaker.JustificationInfo jInfos[]) { + // Do nothing + return 0; + } + } +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/image/BufferedImageGraphics2D.java b/app/src/main/java/org/apache/harmony/awt/gl/image/BufferedImageGraphics2D.java new file mode 100644 index 000000000..f1d64fbec --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/image/BufferedImageGraphics2D.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexey A. Petrenko + * @version $Revision$ + */ +package org.apache.harmony.awt.gl.image; + +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.Rectangle; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.WritableRaster; + +import org.apache.harmony.awt.gl.CommonGraphics2D; +import org.apache.harmony.awt.gl.Surface; +import org.apache.harmony.awt.gl.render.JavaBlitter; +import org.apache.harmony.awt.gl.render.NativeImageBlitter; + +/** + * BufferedImageGraphics2D is implementation of CommonGraphics2D for + * drawing on buffered images. + */ +public class BufferedImageGraphics2D extends CommonGraphics2D { + private BufferedImage bi = null; + private Rectangle bounds = null; + + public BufferedImageGraphics2D(BufferedImage bi) { + super(); + this.bi = bi; + this.bounds = new Rectangle(0, 0, bi.getWidth(), bi.getHeight()); + clip(bounds); + dstSurf = Surface.getImageSurface(bi); + if(dstSurf.isNativeDrawable()){ + blitter = NativeImageBlitter.getInstance(); + }else{ + blitter = JavaBlitter.getInstance(); + } + } + + @Override + public void copyArea(int x, int y, int width, int height, int dx, int dy) { + } + + @Override + public Graphics create() { + BufferedImageGraphics2D res = new BufferedImageGraphics2D(bi); + copyInternalFields(res); + return res; + } + + @Override + public GraphicsConfiguration getDeviceConfiguration() { + return null; + } + + public ColorModel getColorModel() { + return bi.getColorModel(); + } + + public WritableRaster getWritableRaster() { + return bi.getRaster(); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/apache/harmony/awt/gl/image/BufferedImageSource.java b/app/src/main/java/org/apache/harmony/awt/gl/image/BufferedImageSource.java new file mode 100644 index 000000000..0fe25a2e8 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/image/BufferedImageSource.java @@ -0,0 +1,136 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ + +package org.apache.harmony.awt.gl.image; + +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.ComponentColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; +import java.awt.image.DataBufferInt; +import java.awt.image.DirectColorModel; +import java.awt.image.ImageConsumer; +import java.awt.image.ImageProducer; +import java.awt.image.IndexColorModel; +import java.awt.image.WritableRaster; +import java.util.Hashtable; + +public class BufferedImageSource implements ImageProducer { + + private Hashtable properties; + private ColorModel cm; + private WritableRaster raster; + private int width; + private int height; + + private ImageConsumer ic; + + public BufferedImageSource(BufferedImage image, Hashtable properties){ + if(properties == null) { + this.properties = new Hashtable(); + } else { + this.properties = properties; + } + + width = image.getWidth(); + height = image.getHeight(); + cm = image.getColorModel(); + raster = image.getRaster(); + } + + public BufferedImageSource(BufferedImage image){ + this(image, null); + } + + public boolean isConsumer(ImageConsumer ic) { + return (this.ic == ic); + } + + public void startProduction(ImageConsumer ic) { + addConsumer(ic); + } + + public void requestTopDownLeftRightResend(ImageConsumer ic) { + } + + public void removeConsumer(ImageConsumer ic) { + if (this.ic == ic) { + this.ic = null; + } + } + + public void addConsumer(ImageConsumer ic) { + this.ic = ic; + startProduction(); + } + + private void startProduction(){ + try { + ic.setDimensions(width, height); + ic.setProperties(properties); + ic.setColorModel(cm); + ic.setHints(ImageConsumer.TOPDOWNLEFTRIGHT | + ImageConsumer.COMPLETESCANLINES | + ImageConsumer.SINGLEFRAME | + ImageConsumer.SINGLEPASS); + if(cm instanceof IndexColorModel && + raster.getTransferType() == DataBuffer.TYPE_BYTE || + cm instanceof ComponentColorModel && + raster.getTransferType() == DataBuffer.TYPE_BYTE && + raster.getNumDataElements() == 1){ + DataBufferByte dbb = (DataBufferByte) raster.getDataBuffer(); + byte data[] = dbb.getData(); + int off = dbb.getOffset(); + ic.setPixels(0, 0, width, height, cm, data, off, width); + }else if(cm instanceof DirectColorModel && + raster.getTransferType() == DataBuffer.TYPE_INT){ + DataBufferInt dbi = (DataBufferInt) raster.getDataBuffer(); + int data[] = dbi.getData(); + int off = dbi.getOffset(); + ic.setPixels(0, 0, width, height, cm, data, off, width); + }else if(cm instanceof DirectColorModel && + raster.getTransferType() == DataBuffer.TYPE_BYTE){ + DataBufferByte dbb = (DataBufferByte) raster.getDataBuffer(); + byte data[] = dbb.getData(); + int off = dbb.getOffset(); + ic.setPixels(0, 0, width, height, cm, data, off, width); + }else{ + ColorModel rgbCM = ColorModel.getRGBdefault(); + int pixels[] = new int[width]; + Object pix = null; + for(int y = 0; y < height; y++){ + for(int x = 0 ; x < width; x++){ + pix = raster.getDataElements(x, y, pix); + pixels[x] = cm.getRGB(pix); + } + ic.setPixels(0, y, width, 1, rgbCM, pixels, 0, width); + } + } + ic.imageComplete(ImageConsumer.STATICIMAGEDONE); + }catch (NullPointerException e){ + if (ic != null) { + ic.imageComplete(ImageConsumer.IMAGEERROR); + } + } + } + +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/image/ByteArrayDecodingImageSource.java b/app/src/main/java/org/apache/harmony/awt/gl/image/ByteArrayDecodingImageSource.java new file mode 100644 index 000000000..cc6d7cf66 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/image/ByteArrayDecodingImageSource.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +/* + * Created on 10.02.2005 + * + */ +package org.apache.harmony.awt.gl.image; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +public class ByteArrayDecodingImageSource extends DecodingImageSource { + + byte imagedata[]; + int imageoffset; + int imagelength; + + public ByteArrayDecodingImageSource(byte imagedata[], int imageoffset, + int imagelength){ + this.imagedata = imagedata; + this.imageoffset = imageoffset; + this.imagelength = imagelength; + } + + public ByteArrayDecodingImageSource(byte imagedata[]){ + this(imagedata, 0, imagedata.length); + } + + @Override + protected boolean checkConnection() { + return true; + } + + @Override + protected InputStream getInputStream() { + // BEGIN android-modified + // TODO: Why does a ByteArrayInputStream need to be buffered at all? + return new BufferedInputStream(new ByteArrayInputStream(imagedata, + imageoffset, imagelength), 1024); + // END android-modified + } + +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/image/DataBufferListener.java b/app/src/main/java/org/apache/harmony/awt/gl/image/DataBufferListener.java new file mode 100644 index 000000000..8793050a3 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/image/DataBufferListener.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + * Created on 13.03.2006 + * + */ +package org.apache.harmony.awt.gl.image; + +public interface DataBufferListener { + + void dataChanged(); + void dataTaken(); + void dataReleased(); + +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/image/DecodingImageSource.java b/app/src/main/java/org/apache/harmony/awt/gl/image/DecodingImageSource.java new file mode 100644 index 000000000..958d691ce --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/image/DecodingImageSource.java @@ -0,0 +1,261 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ +/* + * Created on 18.01.2005 + */ +package org.apache.harmony.awt.gl.image; + +import java.awt.image.ImageConsumer; +import java.awt.image.ImageProducer; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * This is an abstract class that encapsulates a main part of ImageProducer functionality + * for the images being decoded by the native decoders, like PNG, JPEG and GIF. + * It helps to integrate image decoders into producer/consumer model. It provides + * functionality for working with several decoder instances and several image consumers + * simultaneously. + */ +public abstract class DecodingImageSource implements ImageProducer { + List consumers = new ArrayList(5); + List decoders = new ArrayList(5); + boolean loading; + + ImageDecoder decoder; + + protected abstract boolean checkConnection(); + + protected abstract InputStream getInputStream(); + + public synchronized void addConsumer(ImageConsumer ic) { + if (!checkConnection()) { // No permission for this consumer + ic.imageComplete(ImageConsumer.IMAGEERROR); + return; + } + + ImageConsumer cons = findConsumer(consumers, ic); + + if (cons == null) { // Try to look in the decoders + ImageDecoder d = null; + + // Check for all existing decoders + for (Iterator i = decoders.iterator(); i.hasNext();) { + d = i.next(); + cons = findConsumer(d.consumers, ic); + if (cons != null) { + break; + } + } + } + + if (cons == null) { // Not found, add this consumer + consumers.add(ic); + } + } + + /** + * This method stops sending data to the given consumer + * @param ic - consumer + */ + private void abortConsumer(ImageConsumer ic) { + ic.imageComplete(ImageConsumer.IMAGEERROR); + consumers.remove(ic); + } + + /** + * This method stops sending data to the list of consumers. + * @param consumersList - list of consumers + */ + private void abortAllConsumers(List consumersList) { + for (ImageConsumer imageConsumer : consumersList) { + abortConsumer(imageConsumer); + } + } + + public synchronized void removeConsumer(ImageConsumer ic) { + ImageDecoder d = null; + + // Remove in all existing decoders + for (Iterator i = decoders.iterator(); i.hasNext();) { + d = i.next(); + removeConsumer(d.consumers, ic); + if (d.consumers.size() <= 0) { + d.terminate(); + } + } + + // Remove in the current queue of consumers + removeConsumer(consumers, ic); + } + + /** + * Static implementation of removeConsumer method + * @param consumersList - list of consumers + * @param ic - consumer to be removed + */ + private static void removeConsumer(List consumersList, ImageConsumer ic) { + ImageConsumer cons = null; + + for (Iterator i = consumersList.iterator(); i.hasNext();) { + cons = i.next(); + if (cons.equals(ic)) { + i.remove(); + } + } + } + + public void requestTopDownLeftRightResend(ImageConsumer consumer) { + // Do nothing + } + + public synchronized void startProduction(ImageConsumer ic) { + if (ic != null) { + addConsumer(ic); + } + + if (!loading && consumers.size() > 0) { + ImageLoader.addImageSource(this); + loading = true; + } + } + + public synchronized boolean isConsumer(ImageConsumer ic) { + ImageDecoder d = null; + + // Check for all existing decoders + for (Iterator i = decoders.iterator(); i.hasNext();) { + d = i.next(); + if (findConsumer(d.consumers, ic) != null) { + return true; + } + } + + // Check current queue of consumers + return findConsumer(consumers, ic) != null; + } + + /** + * Checks if the consumer is in the list and returns it it is there + * @param consumersList - list of consumers + * @param ic - consumer + * @return consumer if found, null otherwise + */ + private static ImageConsumer findConsumer(List consumersList, ImageConsumer ic) { + ImageConsumer res = null; + + for (Iterator i = consumersList.iterator(); i.hasNext();) { + res = i.next(); + if (res.equals(ic)) { + return res; + } + } + + return null; + } + + /** + * Use this method to finish decoding or lock the list of consumers + * for a particular decoder + * @param d - decoder + */ + synchronized void lockDecoder(ImageDecoder d) { + if (d == decoder) { + decoder = null; + startProduction(null); + } + } + + /** + * Tries to find an appropriate decoder for the input stream and adds it + * to the list of decoders + * @return created decoder + */ + private ImageDecoder createDecoder() { + InputStream is = getInputStream(); + + ImageDecoder decoder; + + if (is == null) { + decoder = null; + } else { + decoder = ImageDecoder.createDecoder(this, is); + } + + if (decoder != null) { + synchronized (this) { + decoders.add(decoder); + this.decoder = decoder; + loading = false; + consumers = new ArrayList(5); // Reset queue + } + + return decoder; + } + // We were not able to find appropriate decoder + List cs; + synchronized (this) { + cs = consumers; + consumers = new ArrayList(5); + loading = false; + } + abortAllConsumers(cs); + + return null; + } + + /** + * Stop the given decoder and remove it from the list + * @param dr - decoder + */ + private synchronized void removeDecoder(ImageDecoder dr) { + lockDecoder(dr); + decoders.remove(dr); + } + + /** + * This method serves as an entry point. + * It starts the decoder and loads the image data. + */ + public void load() { + synchronized (this) { + if (consumers.size() == 0) { + loading = false; + return; + } + } + + ImageDecoder d = createDecoder(); + if (d != null) { + try { + decoder.decodeImage(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + removeDecoder(d); + abortAllConsumers(d.consumers); + } + } + } +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/image/FileDecodingImageSource.java b/app/src/main/java/org/apache/harmony/awt/gl/image/FileDecodingImageSource.java new file mode 100644 index 000000000..54d466432 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/image/FileDecodingImageSource.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ +/* + * Created on 20.01.2005 + */ +package org.apache.harmony.awt.gl.image; + +import java.io.BufferedInputStream; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; + +public class FileDecodingImageSource extends DecodingImageSource { + String filename; + + public FileDecodingImageSource(String file) { + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkRead(file); + } + + filename = file; + } + + @Override +protected boolean checkConnection() { + SecurityManager security = System.getSecurityManager(); + if (security != null) { + try { + security.checkRead(filename); + } catch (SecurityException e) { + return false; + } + } + + return true; + } + + @Override +protected InputStream getInputStream() { + try { + // BEGIN android-modified + return new BufferedInputStream(new FileInputStream(filename), 8192); + // END android-modified + } catch (FileNotFoundException e) { + return null; + } + } + +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/image/GifDecoder.java b/app/src/main/java/org/apache/harmony/awt/gl/image/GifDecoder.java new file mode 100644 index 000000000..f5ac62e94 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/image/GifDecoder.java @@ -0,0 +1,692 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ +/* +* Created on 27.01.2005 +*/ +package org.apache.harmony.awt.gl.image; + +import java.awt.image.ColorModel; +import java.awt.image.ImageConsumer; +import java.awt.image.IndexColorModel; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Hashtable; +import java.util.List; + +public class GifDecoder extends ImageDecoder { + // initializes proper field IDs + private static native void initIDs(); + + static { + System.loadLibrary("gl"); //$NON-NLS-1$ + initIDs(); + } + + // ImageConsumer hints: common + private static final int baseHints = + ImageConsumer.SINGLEPASS | ImageConsumer.COMPLETESCANLINES | + ImageConsumer.SINGLEFRAME; + // ImageConsumer hints: interlaced + private static final int interlacedHints = + baseHints | ImageConsumer.RANDOMPIXELORDER; + + // Impossible color value - no translucent pixels allowed + static final int IMPOSSIBLE_VALUE = 0x0FFFFFFF; + + // I/O buffer + private static final int BUFFER_SIZE = 1024; + private byte buffer[] = new byte[BUFFER_SIZE]; + + GifDataStream gifDataStream = new GifDataStream(); + GifGraphicBlock currBlock; + + // Pointer to native structure which store decoding state + // between subsequent decoding/IO-suspension cycles + private long hNativeDecoder; // NULL initially + + // Number of bytes eaten by the native decoder + private int bytesConsumed; + + private boolean consumersPrepared; + private Hashtable properties = new Hashtable(); + + // Could be set up by java code or native method when + // transparent pixel index changes or local color table encountered + private boolean forceRGB; + + private byte screenBuffer[]; + private int screenRGBBuffer[]; + + public GifDecoder(DecodingImageSource src, InputStream is) { + super(src, is); + } + + private static native int[] toRGB(byte imageData[], byte colormap[], int transparentColor); + + private static native void releaseNativeDecoder(long hDecoder); + + private native int decode( + byte input[], + int bytesInBuffer, + long hDecoder, + GifDataStream dataStream, + GifGraphicBlock currBlock + ); + + private int[] getScreenRGBBuffer() { + if (screenRGBBuffer == null) { + if (screenBuffer != null) { + int transparentColor = + gifDataStream.logicalScreen.globalColorTable.cm.getTransparentPixel(); + transparentColor = transparentColor > 0 ? transparentColor : IMPOSSIBLE_VALUE; + screenRGBBuffer = + toRGB( + screenBuffer, + gifDataStream.logicalScreen.globalColorTable.colors, + transparentColor + ); + } else { + int size = gifDataStream.logicalScreen.logicalScreenHeight * + gifDataStream.logicalScreen.logicalScreenWidth; + screenRGBBuffer = new int[size]; + } + } + + return screenRGBBuffer; + } + + private void prepareConsumers() { + GifLogicalScreen gls = gifDataStream.logicalScreen; + setDimensions(gls.logicalScreenWidth, + gls.logicalScreenHeight); + setProperties(properties); + + currBlock = gifDataStream.graphicBlocks.get(0); + if (forceRGB) { + setColorModel(ColorModel.getRGBdefault()); + } else { + setColorModel(gls.globalColorTable.getColorModel(currBlock.transparentColor)); + } + + // Fill screen buffer with the background or transparent color + if (forceRGB) { + int fillColor = 0xFF000000; + if (gls.backgroundColor != IMPOSSIBLE_VALUE) { + fillColor = gls.backgroundColor; + } + + Arrays.fill(getScreenRGBBuffer(), fillColor); + } else { + int fillColor = 0; + + if (gls.backgroundColor != IMPOSSIBLE_VALUE) { + fillColor = gls.backgroundColor; + } else { + fillColor = gls.globalColorTable.cm.getTransparentPixel(); + } + + screenBuffer = new byte[gls.logicalScreenHeight*gls.logicalScreenWidth]; + Arrays.fill(screenBuffer, (byte) fillColor); + } + + setHints(interlacedHints); // XXX - always random pixel order + } + + @Override + public void decodeImage() throws IOException { + try { + int bytesRead = 0; + int needBytes, offset, bytesInBuffer = 0; + boolean eosReached = false; + GifGraphicBlock blockToDispose = null; + + // Create new graphic block + if (currBlock == null) { + currBlock = new GifGraphicBlock(); + gifDataStream.graphicBlocks.add(currBlock); + } + + // Read from the input stream + for (;;) { + needBytes = BUFFER_SIZE - bytesInBuffer; + offset = bytesInBuffer; + + bytesRead = inputStream.read(buffer, offset, needBytes); + + if (bytesRead < 0) { + eosReached = true; + bytesRead = 0; + } // Don't break, maybe something left in buffer + + // Keep track on how much bytes left in buffer + bytesInBuffer += bytesRead; + + // Here we pass number of new bytes read from the input stream (bytesRead) + // since native decoder uses java buffer and doesn't have its own + // buffer. So it adds this number to the number of bytes left + // in buffer from the previous call. + int numLines = decode( + buffer, + bytesRead, + hNativeDecoder, + gifDataStream, + currBlock); + + // Keep track on how much bytes left in buffer + bytesInBuffer -= bytesConsumed; + + if ( + !consumersPrepared && + gifDataStream.logicalScreen.completed && + gifDataStream.logicalScreen.globalColorTable.completed && + (currBlock.imageData != null || // Have transparent pixel filled + currBlock.rgbImageData != null) + ) { + prepareConsumers(); + consumersPrepared = true; + } + + if (bytesConsumed < 0) { + break; // Error exit + } + + if (currBlock != null) { + if (numLines != 0) { + // Dispose previous image only before showing next + if (blockToDispose != null) { + blockToDispose.dispose(); + blockToDispose = null; + } + + currBlock.sendNewData(this, numLines); + } + + if (currBlock.completed && hNativeDecoder != 0) { + blockToDispose = currBlock; // Dispose only before showing new pixels + currBlock = new GifGraphicBlock(); + gifDataStream.graphicBlocks.add(currBlock); + } + } + + if (hNativeDecoder == 0) { + break; + } + + if (eosReached && numLines == 0) { // Maybe image is truncated... + releaseNativeDecoder(hNativeDecoder); + break; + } + } + } finally { + closeStream(); + } + + // Here all animation goes + // Repeat image loopCount-1 times or infinitely if loopCount = 0 + if (gifDataStream.loopCount != 1) { + if (currBlock.completed == false) { + gifDataStream.graphicBlocks.remove(currBlock); + } + + int numFrames = gifDataStream.graphicBlocks.size(); + // At first last block will be disposed + GifGraphicBlock gb = + gifDataStream.graphicBlocks.get(numFrames-1); + + ImageLoader.beginAnimation(); + + while (gifDataStream.loopCount != 1) { + if (gifDataStream.loopCount != 0) { + gifDataStream.loopCount--; + } + + // Show all frames + for (int i=0; i graphicBlocks = new ArrayList(10); // Of GifGraphicBlocks + + // Comments from the image + String comments[]; + } + + class GifLogicalScreen { + // Indicates that reading of this block accomplished + boolean completed = false; + + int logicalScreenWidth; + int logicalScreenHeight; + + int backgroundColor = IMPOSSIBLE_VALUE; + + GifColorTable globalColorTable = new GifColorTable(); + } + + class GifGraphicBlock { + // Indicates that reading of this block accomplished + boolean completed = false; + + final static int DISPOSAL_NONE = 0; + final static int DISPOSAL_NODISPOSAL = 1; + final static int DISPOSAL_BACKGROUND = 2; + final static int DISPOSAL_RESTORE = 3; + + int disposalMethod; + int delayTime; // Multiplied by 10 already + int transparentColor = IMPOSSIBLE_VALUE; + + int imageLeft; + int imageTop; + int imageWidth; + int imageHeight; + + // Auxilliary variables to minimize computations + int imageRight; + int imageBottom; + + boolean interlace; + + // Don't need local color table - if it is specified + // image data are converted to RGB in the native code + + byte imageData[] = null; + int rgbImageData[] = null; + + private int currY = 0; // Current output scanline + + int[] getRgbImageData() { + if (rgbImageData == null) { + rgbImageData = + toRGB( + imageData, + gifDataStream.logicalScreen.globalColorTable.colors, + transparentColor + ); + if (transparentColor != IMPOSSIBLE_VALUE) { + transparentColor = + gifDataStream.logicalScreen.globalColorTable.cm.getRGB(transparentColor); + transparentColor &= 0x00FFFFFF; + } + } + return rgbImageData; + } + + private void replaceTransparentPixels(int numLines) { + List graphicBlocks = gifDataStream.graphicBlocks; + int prevBlockIndex = graphicBlocks.indexOf(this) - 1; + + if (prevBlockIndex >= 0) { + int maxY = currY + numLines + imageTop; + int offset = currY * imageWidth; + + // Update right and bottom coordinates + imageRight = imageLeft + imageWidth; + imageBottom = imageTop + imageHeight; + + int globalWidth = gifDataStream.logicalScreen.logicalScreenWidth; + int pixelValue, imageOffset; + int rgbData[] = forceRGB ? getRgbImageData() : null; + + for (int y = currY + imageTop; y < maxY; y++) { + imageOffset = globalWidth * y + imageLeft; + for (int x = imageLeft; x < imageRight; x++) { + pixelValue = forceRGB ? + rgbData[offset] : + imageData[offset] & 0xFF; + if (pixelValue == transparentColor) { + if (forceRGB) { + pixelValue = getScreenRGBBuffer() [imageOffset]; + rgbData[offset] = pixelValue; + } else { + pixelValue = screenBuffer [imageOffset]; + imageData[offset] = (byte) pixelValue; + } + } + offset++; + imageOffset++; + } // for + } // for + + } // if (prevBlockIndex >= 0) + } + + public void sendNewData(GifDecoder decoder, int numLines) { + // Get values for transparent pixels + // from the perevious frames + if (transparentColor != IMPOSSIBLE_VALUE) { + replaceTransparentPixels(numLines); + } + + if (forceRGB) { + decoder.setPixels( + imageLeft, + imageTop + currY, + imageWidth, + numLines, + ColorModel.getRGBdefault(), + getRgbImageData(), + currY*imageWidth, + imageWidth + ); + } else { + decoder.setPixels( + imageLeft, + imageTop + currY, + imageWidth, + numLines, + null, + imageData, + currY*imageWidth, + imageWidth + ); + } + + currY += numLines; + } + + public void dispose() { + imageComplete(ImageConsumer.SINGLEFRAMEDONE); + + // Show current frame until delayInterval will not elapse + if (delayTime > 0) { + try { + Thread.sleep(delayTime); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } else { + Thread.yield(); // Allow consumers to consume data + } + + // Don't dispose if image is outside of the visible area + if (imageLeft > gifDataStream.logicalScreen.logicalScreenWidth || + imageTop > gifDataStream.logicalScreen.logicalScreenHeight) { + disposalMethod = DISPOSAL_NONE; + } + + switch(disposalMethod) { + case DISPOSAL_BACKGROUND: { + if (forceRGB) { + getRgbImageData(); // Ensure that transparentColor is RGB, not index + + int data[] = new int[imageWidth*imageHeight]; + + // Compatibility: Fill with transparent color if we have one + if (transparentColor != IMPOSSIBLE_VALUE) { + Arrays.fill( + data, + transparentColor + ); + } else { + Arrays.fill( + data, + gifDataStream.logicalScreen.backgroundColor + ); + } + + setPixels( + imageLeft, + imageTop, + imageWidth, + imageHeight, + ColorModel.getRGBdefault(), + data, + 0, + imageWidth + ); + + sendToScreenBuffer(data); + } else { + byte data[] = new byte[imageWidth*imageHeight]; + + // Compatibility: Fill with transparent color if we have one + if (transparentColor != IMPOSSIBLE_VALUE) { + Arrays.fill( + data, + (byte) transparentColor + ); + } else { + Arrays.fill( + data, + (byte) gifDataStream.logicalScreen.backgroundColor + ); + } + + setPixels( + imageLeft, + imageTop, + imageWidth, + imageHeight, + null, + data, + 0, + imageWidth + ); + + sendToScreenBuffer(data); + } + break; + } + case DISPOSAL_RESTORE: { + screenBufferToScreen(); + break; + } + case DISPOSAL_NONE: + case DISPOSAL_NODISPOSAL: + default: { + // Copy transmitted data to the screen buffer + Object data = forceRGB ? (Object) getRgbImageData() : imageData; + sendToScreenBuffer(data); + break; + } + } + } + + private void sendToScreenBuffer(Object data) { + int dataInt[]; + byte dataByte[]; + + int width = gifDataStream.logicalScreen.logicalScreenWidth; + + + if (forceRGB) { + dataInt = (int[]) data; + + if (imageWidth == width) { + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(dataInt, + 0, + getScreenRGBBuffer(), + imageLeft + imageTop*width, + dataInt.length + ); + } else { // Each scanline + copyScanlines(dataInt, getScreenRGBBuffer(), width); + } + } else { + dataByte = (byte[]) data; + + if (imageWidth == width) { + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(dataByte, + 0, + screenBuffer, + imageLeft + imageTop*width, + dataByte.length + ); + } else { // Each scanline + copyScanlines(dataByte, screenBuffer, width); + } + } + } // sendToScreenBuffer + + private void copyScanlines(Object src, Object dst, int width) { + for (int i=0; i 0) { + if (transparentColor == IMPOSSIBLE_VALUE) { + return cm = + new IndexColorModel(8, size, colors, 0, false); + } + + if (transparentColor > size) { + size = transparentColor + 1; + } + return cm = + new IndexColorModel(8, size, colors, 0, false, transparentColor); + } + + return cm = null; // Force default ARGB color model + } + } +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/image/ImageDecoder.java b/app/src/main/java/org/apache/harmony/awt/gl/image/ImageDecoder.java new file mode 100644 index 000000000..d16128e55 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/image/ImageDecoder.java @@ -0,0 +1,258 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ +/* + * Created on 18.01.2005 + */ +package org.apache.harmony.awt.gl.image; + +import com.android.internal.awt.AndroidImageDecoder; + +import java.awt.image.ColorModel; +import java.awt.image.ImageConsumer; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ConcurrentModificationException; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; + + +/** + * This class contains common functionality for all image decoders. + */ +public abstract class ImageDecoder { + + /** Image types */ + public static final int GENERIC_DECODER = 0; + public static final int JPG_DECODER = 1; + public static final int GIF_DECODER = 2; + public static final int PNG_DECODER = 3; + + private static final int MAX_BYTES_IN_SIGNATURE = 8; + + protected List consumers; + protected InputStream inputStream; + protected DecodingImageSource src; + + protected boolean terminated; + + /** + * Chooses appropriate image decoder by looking into input stream and checking + * the image signature. + * @param src - image producer, required for passing data to it from the + * created decoder via callbacks + * @param is - stream + * @return decoder + */ + static ImageDecoder createDecoder(DecodingImageSource src, InputStream is) { + InputStream markable; + + if (!is.markSupported()) { + // BEGIN android-modified + markable = new BufferedInputStream(is, 8192); + // END android-modified + } else { + markable = is; + } + + // Read the signature from the stream and then reset it back + try { + markable.mark(MAX_BYTES_IN_SIGNATURE); + + byte[] signature = new byte[MAX_BYTES_IN_SIGNATURE]; + markable.read(signature, 0, MAX_BYTES_IN_SIGNATURE); + markable.reset(); + + if ((signature[0] & 0xFF) == 0xFF && + (signature[1] & 0xFF) == 0xD8 && + (signature[2] & 0xFF) == 0xFF) { // JPEG + return loadDecoder(PNG_DECODER, src, is); + } else if ((signature[0] & 0xFF) == 0x47 && // G + (signature[1] & 0xFF) == 0x49 && // I + (signature[2] & 0xFF) == 0x46) { // F + return loadDecoder(GIF_DECODER, src, is); + } else if ((signature[0] & 0xFF) == 137 && // PNG signature: 137 80 78 71 13 10 26 10 + (signature[1] & 0xFF) == 80 && + (signature[2] & 0xFF) == 78 && + (signature[3] & 0xFF) == 71 && + (signature[4] & 0xFF) == 13 && + (signature[5] & 0xFF) == 10 && + (signature[6] & 0xFF) == 26 && + (signature[7] & 0xFF) == 10) { + return loadDecoder(JPG_DECODER, src, is); + } + + return loadDecoder(GENERIC_DECODER, src, is); + + } catch (IOException e) { // Silently + } + + return null; + } + + /* + * In the future, we might return different decoders for differen image types. + * But for now, we always return the generic one. + * Also: we could add a factory to load image decoder. + */ + private static ImageDecoder loadDecoder(int type, DecodingImageSource src, + InputStream is) { + return new AndroidImageDecoder(src, is); + } + + protected ImageDecoder(DecodingImageSource _src, InputStream is) { + src = _src; + consumers = src.consumers; + inputStream = is; + } + + public abstract void decodeImage() throws IOException; + + public synchronized void closeStream() { + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException e) { + } + } + } + + /** + * Stops the decoding by interrupting the current decoding thread. + * Used when all consumers are removed and there's no more need to + * run the decoder. + */ + public void terminate() { + src.lockDecoder(this); + closeStream(); + + AccessController.doPrivileged( + new PrivilegedAction() { + public Void run() { + Thread.currentThread().interrupt(); + return null; + } + } + ); + + terminated = true; + } + + protected void setDimensions(int w, int h) { + if (terminated) { + return; + } + + for (ImageConsumer ic : consumers) { + ic.setDimensions(w, h); + } + } + + protected void setProperties(Hashtable props) { + if (terminated) { + return; + } + + for (ImageConsumer ic : consumers) { + ic.setProperties(props); + } + } + + protected void setColorModel(ColorModel cm) { + if (terminated) { + return; + } + + for (ImageConsumer ic : consumers) { + ic.setColorModel(cm); + } + } + + protected void setHints(int hints) { + if (terminated) { + return; + } + + for (ImageConsumer ic : consumers) { + ic.setHints(hints); + } + } + + protected void setPixels( + int x, int y, + int w, int h, + ColorModel model, + byte pix[], + int off, int scansize + ) { + if (terminated) { + return; + } + + src.lockDecoder(this); + + for (ImageConsumer ic : consumers) { + ic.setPixels(x, y, w, h, model, pix, off, scansize); + } + } + + protected void setPixels( + int x, int y, + int w, int h, + ColorModel model, + int pix[], + int off, int scansize + ) { + if (terminated) { + return; + } + + src.lockDecoder(this); + + for (ImageConsumer ic : consumers) { + ic.setPixels(x, y, w, h, model, pix, off, scansize); + } + } + + protected void imageComplete(int status) { + if (terminated) { + return; + } + + src.lockDecoder(this); + + ImageConsumer ic = null; + + for (Iterator i = consumers.iterator(); i.hasNext();) { + try { + ic = i.next(); + } catch (ConcurrentModificationException e) { + i = consumers.iterator(); + continue; + } + ic.imageComplete(status); + } + } + +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/image/ImageLoader.java b/app/src/main/java/org/apache/harmony/awt/gl/image/ImageLoader.java new file mode 100644 index 000000000..5c7d18032 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/image/ImageLoader.java @@ -0,0 +1,208 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ +/* + * Created on 18.01.2005 + */ +package org.apache.harmony.awt.gl.image; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +/** + * This class provides functionality for simultaneous loading of + * several images and running animation. + */ +public class ImageLoader extends Thread { + // Contains ImageLoader objects + // and queue of image sources waiting to be loaded + static class ImageLoadersStorage { + private static final int MAX_THREADS = 5; + private static final int TIMEOUT = 4000; + static ImageLoadersStorage instance; + + List queue = new LinkedList(); + List loaders = new ArrayList(MAX_THREADS); + + private int freeLoaders; + + private ImageLoadersStorage() {} + + static ImageLoadersStorage getStorage() { + if (instance == null) { + instance = new ImageLoadersStorage(); + } + + return instance; + } + } + + ImageLoader() { + super(); + setDaemon(true); + } + + /** + * This method creates a new thread which is able to load an image + * or run animation (if the number of existing loader threads does not + * exceed the limit). + */ + private static void createLoader() { + final ImageLoadersStorage storage = ImageLoadersStorage.getStorage(); + + synchronized(storage.loaders) { + if (storage.loaders.size() < ImageLoadersStorage.MAX_THREADS) { + AccessController.doPrivileged( + new PrivilegedAction() { + public Void run() { + ImageLoader loader = new ImageLoader(); + storage.loaders.add(loader); + loader.start(); + return null; + } + }); + } + } + } + + /** + * Adds a new image source to the queue and starts a new loader + * thread if required + * @param imgSrc - image source + */ + public static void addImageSource(DecodingImageSource imgSrc) { + ImageLoadersStorage storage = ImageLoadersStorage.getStorage(); + synchronized(storage.queue) { + if (!storage.queue.contains(imgSrc)) { + storage.queue.add(imgSrc); + } + if (storage.freeLoaders == 0) { + createLoader(); + } + + storage.queue.notify(); + } + } + + /** + * Waits for a new ImageSource until timout expires. + * Loader thread will terminate after returning from this method + * if timeout expired and image source was not picked up from the queue. + * @return image source picked up from the queue or null if timeout expired + */ + private static DecodingImageSource getWaitingImageSource() { + ImageLoadersStorage storage = ImageLoadersStorage.getStorage(); + + synchronized(storage.queue) { + DecodingImageSource isrc = null; + + if (storage.queue.size() == 0) { + try { + storage.freeLoaders++; + storage.queue.wait(ImageLoadersStorage.TIMEOUT); + } catch (InterruptedException e) { + return null; + } finally { + storage.freeLoaders--; + } + } + + if (storage.queue.size() > 0) { + isrc = storage.queue.get(0); + storage.queue.remove(0); + } + + return isrc; + } + } + + /** + * Entry point of the loader thread. Picks up image sources and + * runs decoders for them while there are available image sources in the queue. + * If there are no and timeout expires it terminates. + */ + @Override + public void run() { + ImageLoadersStorage storage = ImageLoadersStorage.getStorage(); + + try { + while (storage.loaders.contains(this)) { + Thread.interrupted(); // Reset the interrupted flag + DecodingImageSource isrc = getWaitingImageSource(); + if (isrc != null) { + try { + isrc.load(); + } catch (Exception e) { + e.printStackTrace(); + } + } else { + break; // Don't wait if timeout expired - terminate loader + } + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + synchronized(storage.loaders) { + storage.loaders.remove(Thread.currentThread()); + } + } + } + + /** + * Removes current thread from loaders (so we are able + * to create more loaders) and decreases its priority. + */ + static void beginAnimation() { + ImageLoadersStorage storage = ImageLoadersStorage.getStorage(); + Thread currThread = Thread.currentThread(); + + synchronized(storage) { + storage.loaders.remove(currThread); + + if (storage.freeLoaders < storage.queue.size()) { + createLoader(); + } + } + + currThread.setPriority(Thread.MIN_PRIORITY); + } + + /** + * Sends the current thread to wait for the new images to load + * if there are free placeholders for loaders + */ + static void endAnimation() { + ImageLoadersStorage storage = ImageLoadersStorage.getStorage(); + Thread currThread = Thread.currentThread(); + + synchronized(storage) { + if (storage.loaders.size() < ImageLoadersStorage.MAX_THREADS && + !storage.loaders.contains(currThread) + ) { + storage.loaders.add(currThread); + } + } + + currThread.setPriority(Thread.NORM_PRIORITY); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/apache/harmony/awt/gl/image/JpegDecoder.java b/app/src/main/java/org/apache/harmony/awt/gl/image/JpegDecoder.java new file mode 100644 index 000000000..2e64427f0 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/image/JpegDecoder.java @@ -0,0 +1,231 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The ASF licenses this file to You under the Apache License, Version 2.0 +* (the "License"); you may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ +package org.apache.harmony.awt.gl.image; + +import java.awt.image.*; +import java.awt.color.ColorSpace; +import java.awt.*; +import java.io.IOException; +import java.io.InputStream; +import java.util.Hashtable; + +import org.apache.harmony.awt.internal.nls.Messages; + +public class JpegDecoder extends ImageDecoder { + // Only 2 output colorspaces expected. Others are converted into + // these ones. + // 1. Grayscale + public static final int JCS_GRAYSCALE = 1; + // 2. RGB + public static final int JCS_RGB = 2; + + // Flags for the consumer, progressive JPEG + private static final int hintflagsProgressive = + ImageConsumer.SINGLEFRAME | // JPEG is a static image + ImageConsumer.TOPDOWNLEFTRIGHT | // This order is only one possible + ImageConsumer.COMPLETESCANLINES; // Don't deliver incomplete scanlines + // Flags for the consumer, singlepass JPEG + private static final int hintflagsSingle = + ImageConsumer.SINGLEPASS | + hintflagsProgressive; + + // Buffer for the stream + private static final int BUFFER_SIZE = 1024; + private byte buffer[] = new byte[BUFFER_SIZE]; + + // 3 possible color models only + private static ColorModel cmRGB; + private static ColorModel cmGray; + + // initializes proper field IDs + private static native void initIDs(); + + // Pointer to native structure which store decoding state + // between subsequent decoding/IO-suspension cycles + private long hNativeDecoder = 0; // NULL initially + + private boolean headerDone = false; + + // Next 4 members are filled by the native method (decompress). + // We can simply check if imageWidth is still negative to find + // out if they are already filled. + private int imageWidth = -1; + private int imageHeight = -1; + private boolean progressive = false; + private int jpegColorSpace = 0; + + // Stores number of bytes consumed by the native decoder + private int bytesConsumed = 0; + // Stores current scanline returned by the decoder + private int currScanline = 0; + + private ColorModel cm = null; + + static { + System.loadLibrary("jpegdecoder"); //$NON-NLS-1$ + + cmGray = new ComponentColorModel( + ColorSpace.getInstance(ColorSpace.CS_GRAY), + false, false, + Transparency.OPAQUE, DataBuffer.TYPE_BYTE + ); + + // Create RGB color model + cmRGB = new DirectColorModel(24, 0xFF0000, 0xFF00, 0xFF); + + initIDs(); + } + + public JpegDecoder(DecodingImageSource src, InputStream is) { + super(src, is); + } + + /* + public JpegDecoder(InputStream iStream, ImageConsumer iConsumer) { + inputStream = iStream; + consumer = iConsumer; + } + */ + + /** + * @return - not NULL if call is successful + */ + private native Object decode( + byte[] input, + int bytesInBuffer, + long hDecoder); + + private static native void releaseNativeDecoder(long hDecoder); + + @Override + public void decodeImage() throws IOException { + try { + int bytesRead = 0, dataLength = 0; + boolean eosReached = false; + int needBytes, offset, bytesInBuffer = 0; + byte byteOut[] = null; + int intOut[] = null; + // Read from the input stream + for (;;) { + needBytes = BUFFER_SIZE - bytesInBuffer; + offset = bytesInBuffer; + + bytesRead = inputStream.read(buffer, offset, needBytes); + + if (bytesRead < 0) { + bytesRead = 0;//break; + eosReached = true; + } // Don't break, maybe something left in buffer + + // Keep track on how much bytes left in buffer + bytesInBuffer += bytesRead; + + // Here we pass overall number of bytes left in the java buffer + // (bytesInBuffer) since jpeg decoder has its own buffer and consumes + // as many bytes as it can. If there are any unconsumed bytes + // it didn't add them to its buffer... + Object arr = decode( + buffer, + bytesInBuffer, + hNativeDecoder); + + // Keep track on how much bytes left in buffer + bytesInBuffer -= bytesConsumed; + + if (!headerDone && imageWidth != -1) { + returnHeader(); + headerDone = true; + } + + if (bytesConsumed < 0) { + break; // Error exit + } + + if (arr instanceof byte[]) { + byteOut = (byte[]) arr; + dataLength = byteOut.length; + returnData(byteOut, currScanline); + } else if (arr instanceof int[]) { + intOut = (int[]) arr; + dataLength = intOut.length; + returnData(intOut, currScanline); + } else { + dataLength = 0; + } + + if (hNativeDecoder == 0) { + break; + } + + if (dataLength == 0 && eosReached) { + releaseNativeDecoder(hNativeDecoder); + break; // Probably image is truncated + } + } + imageComplete(ImageConsumer.STATICIMAGEDONE); + } catch (IOException e) { + throw e; + } finally { + closeStream(); + } + } + + public void returnHeader() { + setDimensions(imageWidth, imageHeight); + + switch (jpegColorSpace) { + case JCS_GRAYSCALE: cm = cmGray; break; + case JCS_RGB: cm = cmRGB; break; + default: + // awt.3D=Unknown colorspace + throw new IllegalArgumentException(Messages.getString("awt.3D")); //$NON-NLS-1$ + } + setColorModel(cm); + + setHints(progressive ? hintflagsProgressive : hintflagsSingle); + + setProperties(new Hashtable()); // Empty + } + + // Send the data to the consumer + public void returnData(int data[], int currScanLine) { + // Send 1 or more scanlines to the consumer. + int numScanlines = data.length / imageWidth; + if (numScanlines > 0) { + setPixels( + 0, currScanLine - numScanlines, + imageWidth, numScanlines, + cm, data, 0, imageWidth + ); + } + } + + public void returnData(byte data[], int currScanLine) { + int numScanlines = data.length / imageWidth; + if (numScanlines > 0) { + setPixels( + 0, currScanLine - numScanlines, + imageWidth, numScanlines, + cm, data, 0, imageWidth + ); + } + } +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/image/OffscreenImage.java b/app/src/main/java/org/apache/harmony/awt/gl/image/OffscreenImage.java new file mode 100644 index 000000000..81c0ea63c --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/image/OffscreenImage.java @@ -0,0 +1,532 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +/* + * Created on 22.12.2004 + * + */ +package org.apache.harmony.awt.gl.image; + +import java.awt.Graphics; +import java.awt.Image; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.ComponentColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; +import java.awt.image.DataBufferInt; +import java.awt.image.DirectColorModel; +import java.awt.image.ImageConsumer; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.image.IndexColorModel; +import java.awt.image.WritableRaster; +import java.util.Hashtable; +import java.util.Vector; + +import org.apache.harmony.awt.gl.ImageSurface; +import org.apache.harmony.awt.internal.nls.Messages; + + +/** + * This class represent implementation of abstract Image class + */ +public class OffscreenImage extends Image implements ImageConsumer { + + static final ColorModel rgbCM = ColorModel.getRGBdefault(); + ImageProducer src; + BufferedImage image; + ColorModel cm; + WritableRaster raster; + boolean isIntRGB; + Hashtable properties; + Vector observers; + int width; + int height; + int imageState; + int hints; + private boolean producing; + private ImageSurface imageSurf; + + public OffscreenImage(ImageProducer ip){ + imageState = 0; + src = ip; + width = -1; + height = -1; + observers = new Vector(); + producing = false; + } + + @Override + public Object getProperty(String name, ImageObserver observer) { + if(name == null) { + // awt.38=Property name is not defined + throw new NullPointerException(Messages.getString("awt.38")); //$NON-NLS-1$ + } + if(properties == null){ + addObserver(observer); + startProduction(); + if(properties == null) { + return null; + } + } + Object prop = properties.get(name); + if(prop == null) { + prop = UndefinedProperty; + } + return prop; + } + + @Override + public ImageProducer getSource() { + return src; + } + + @Override + public int getWidth(ImageObserver observer) { + if((imageState & ImageObserver.WIDTH) == 0){ + addObserver(observer); + startProduction(); + if((imageState & ImageObserver.WIDTH) == 0) { + return -1; + } + } + return width; + } + + @Override + public int getHeight(ImageObserver observer) { + if((imageState & ImageObserver.HEIGHT) == 0){ + addObserver(observer); + startProduction(); + if((imageState & ImageObserver.HEIGHT) == 0) { + return -1; + } + } + return height; + } + + @Override + public Graphics getGraphics() { + // awt.39=This method is not implemented for image obtained from ImageProducer + throw new UnsupportedOperationException(Messages.getString("awt.39")); //$NON-NLS-1$ + } + + @Override + public void flush() { + stopProduction(); + imageUpdate(this, ImageObserver.ABORT, -1, -1, -1, -1); + imageState &= ~ImageObserver.ERROR; + imageState = 0; + image = null; + cm = null; + raster = null; + hints = 0; + width = -1; + height = -1; + } + + public void setProperties(Hashtable properties) { + this.properties = properties; + imageUpdate(this, ImageObserver.PROPERTIES, 0, 0, width, height); + } + + public void setColorModel(ColorModel cm) { + this.cm = cm; + } + + /* + * We suppose what in case loading JPEG image then image has DirectColorModel + * and for infill image Raster will use setPixels method with int array. + * + * In case loading GIF image, for raster infill, is used setPixels method with + * byte array and Color Model is IndexColorModel. But Color Model may + * be changed during this process. Then is called setPixels method with + * int array and image force to default color model - int ARGB. The rest + * pixels are sending in DirectColorModel. + */ + public void setPixels(int x, int y, int w, int h, ColorModel model, + int[] pixels, int off, int scansize) { + if(raster == null){ + if(cm == null){ + if(model == null) { + // awt.3A=Color Model is null + throw new NullPointerException(Messages.getString("awt.3A")); //$NON-NLS-1$ + } + cm = model; + } + createRaster(); + } + + if(model == null) { + model = cm; + } + if(cm != model){ + forceToIntARGB(); + } + + if(cm == model && model.getTransferType() == DataBuffer.TYPE_INT && + raster.getNumDataElements() == 1){ + + DataBufferInt dbi = (DataBufferInt) raster.getDataBuffer(); + int data[] = dbi.getData(); + int scanline = raster.getWidth(); + int rof = dbi.getOffset() + y * scanline + x; + for(int lineOff = off, line = y; line < y + h; + line++, lineOff += scansize, rof += scanline){ + + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(pixels, lineOff, data, rof, w); + } + + }else if(isIntRGB){ + int buff[] = new int[w]; + DataBufferInt dbi = (DataBufferInt) raster.getDataBuffer(); + int data[] = dbi.getData(); + int scanline = raster.getWidth(); + int rof = dbi.getOffset() + y * scanline + x; + for (int sy = y, sOff = off; sy < y + h; sy++, sOff += scansize, + rof += scanline) { + + for (int sx = x, idx = 0; sx < x + w; sx++, idx++) { + buff[idx] = model.getRGB(pixels[sOff + idx]); + } + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(buff, 0, data, rof, w); + } + }else{ + Object buf = null; + for (int sy = y, sOff = off; sy < y + h; sy++, sOff += scansize) { + for (int sx = x, idx = 0; sx < x + w; sx++, idx++) { + int rgb = model.getRGB(pixels[sOff + idx]); + buf = cm.getDataElements(rgb, buf); + raster.setDataElements(sx, sy, buf); + } + } + } + + if (imageSurf != null) { + imageSurf.invalidate(); + } + + imageUpdate(this, ImageObserver.SOMEBITS, 0, 0, width, height); + } + + public void setPixels(int x, int y, int w, int h, ColorModel model, + byte[] pixels, int off, int scansize) { + + if(raster == null){ + if(cm == null){ + if(model == null) { + // awt.3A=Color Model is null + throw new NullPointerException(Messages.getString("awt.3A")); //$NON-NLS-1$ + } + cm = model; + } + createRaster(); + } + if(model == null) { + model = cm; + } + if(model != cm){ + forceToIntARGB(); + } + + if(isIntRGB){ + int buff[] = new int[w]; + IndexColorModel icm = (IndexColorModel) model; + int colorMap[] = new int[icm.getMapSize()]; + icm.getRGBs(colorMap); + DataBufferInt dbi = (DataBufferInt) raster.getDataBuffer(); + int data[] = dbi.getData(); + int scanline = raster.getWidth(); + int rof = dbi.getOffset() + y * scanline + x; + if(model instanceof IndexColorModel){ + + for (int sy = y, sOff = off; sy < y + h; sy++, sOff += scansize, + rof += scanline) { + for (int sx = x, idx = 0; sx < x + w; sx++, idx++) { + buff[idx] = colorMap[pixels[sOff + idx] & 0xff]; + } + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(buff, 0, data, rof, w); + } + }else{ + + for (int sy = y, sOff = off; sy < y + h; sy++, sOff += scansize, + rof += scanline) { + for (int sx = x, idx = 0; sx < x + w; sx++, idx++) { + buff[idx] = model.getRGB(pixels[sOff + idx] & 0xff); + } + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(buff, 0, data, rof, w); + } + } + }else if(model == cm && model.getTransferType() == DataBuffer.TYPE_BYTE && + raster.getNumDataElements() == 1){ + + DataBufferByte dbb = (DataBufferByte)raster.getDataBuffer(); + byte data[] = dbb.getData(); + int scanline = raster.getWidth(); + int rof = dbb.getOffset() + y * scanline + x; + for(int lineOff = off, line = y; line < y + h; + line++, lineOff += scansize, rof += scanline){ + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(pixels, lineOff, data, rof, w); + } + // BEGIN android-added (taken from newer Harmony) + }else if(model == cm && model.getTransferType() == DataBuffer.TYPE_BYTE && + cm instanceof ComponentColorModel){ + + int nc = cm.getNumComponents(); + byte stride[] = new byte[scansize]; + for (int sy = y, sOff = off; sy < y + h; sy++, sOff += scansize) { + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(pixels, sOff, stride, 0, scansize); + + raster.setDataElements(x, sy, w, 1, stride); + } + // END android-added + }else { + for (int sy = y, sOff = off; sy < y + h; sy++, sOff += scansize) { + for (int sx = x, idx = 0; sx < x + w; sx++, idx++) { + int rgb = model.getRGB(pixels[sOff + idx] & 0xff); + raster.setDataElements(sx, sy, cm.getDataElements(rgb, null)); + } + } + } + + if (imageSurf != null) { + imageSurf.invalidate(); + } + + imageUpdate(this, ImageObserver.SOMEBITS, 0, 0, width, height); + } + + public void setDimensions(int width, int height) { + if(width <= 0 || height <= 0){ + imageComplete(ImageObserver.ERROR); + return; + } + + this.width = width; + this.height = height; + imageUpdate(this, (ImageObserver.HEIGHT | ImageObserver.WIDTH), + 0, 0, width, height); + } + + public void setHints(int hints) { + this.hints = hints; + } + + public void imageComplete(int state) { + int flag; + switch(state){ + case IMAGEABORTED: + flag = ImageObserver.ABORT; + break; + case IMAGEERROR: + flag = ImageObserver.ERROR | ImageObserver.ABORT; + break; + case SINGLEFRAMEDONE: + flag = ImageObserver.FRAMEBITS; + break; + case STATICIMAGEDONE: + flag = ImageObserver.ALLBITS; + break; + default: + // awt.3B=Incorrect ImageConsumer completion status + throw new IllegalArgumentException(Messages.getString("awt.3B")); //$NON-NLS-1$ + } + imageUpdate(this, flag, 0, 0, width, height); + + if((flag & (ImageObserver.ERROR | ImageObserver.ABORT | + ImageObserver.ALLBITS)) != 0 ) { + stopProduction(); + observers.removeAllElements(); + } + } + + public /*synchronized*/ BufferedImage getBufferedImage(){ + if(image == null){ + ColorModel model = getColorModel(); + WritableRaster wr = getRaster(); + if(model != null && wr != null) { + image = new BufferedImage(model, wr, model.isAlphaPremultiplied(), null); + } + } + return image; + } + + public /*synchronized*/ int checkImage(ImageObserver observer){ + addObserver(observer); + return imageState; + } + + public /*synchronized*/ boolean prepareImage(ImageObserver observer){ + if((imageState & ImageObserver.ERROR) != 0){ + if(observer != null){ + observer.imageUpdate(this, ImageObserver.ERROR | + ImageObserver.ABORT, -1, -1, -1, -1); + } + return false; + } + if((imageState & ImageObserver.ALLBITS) != 0) { + return true; + } + addObserver(observer); + startProduction(); + return ((imageState & ImageObserver.ALLBITS) != 0); + } + + public /*synchronized*/ ColorModel getColorModel(){ + if(cm == null) { + startProduction(); + } + return cm; + } + + public /*synchronized*/ WritableRaster getRaster(){ + if(raster == null) { + startProduction(); + } + return raster; + } + + public int getState(){ + return imageState; + } + + private /*synchronized*/ void addObserver(ImageObserver observer){ + if(observer != null){ + if(observers.contains(observer)) { + return; + } + if((imageState & ImageObserver.ERROR) != 0){ + observer.imageUpdate(this, ImageObserver.ERROR | + ImageObserver.ABORT, -1, -1, -1, -1); + return; + } + if((imageState & ImageObserver.ALLBITS) != 0){ + observer.imageUpdate(this, imageState, 0, 0, width, height); + return; + } + observers.addElement(observer); + } + } + + private synchronized void startProduction(){ + if(!producing){ + imageState &= ~ImageObserver.ABORT; + producing = true; + src.startProduction(this); + } + } + + private synchronized void stopProduction(){ + producing = false; + src.removeConsumer(this); + } + + private void createRaster(){ + try{ + raster = cm.createCompatibleWritableRaster(width, height); + isIntRGB = false; + if(cm instanceof DirectColorModel){ + DirectColorModel dcm = (DirectColorModel) cm; + if(dcm.getTransferType() == DataBuffer.TYPE_INT && + dcm.getRedMask() == 0xff0000 && + dcm.getGreenMask() == 0xff00 && + dcm.getBlueMask() == 0xff){ + isIntRGB = true; + } + } + }catch(Exception e){ + cm = ColorModel.getRGBdefault(); + raster = cm.createCompatibleWritableRaster(width, height); + isIntRGB = true; + } + } + + private /*synchronized*/ void imageUpdate(Image img, int infoflags, int x, int y, + int width, int height){ + + imageState |= infoflags; + for (ImageObserver observer : observers) { + observer.imageUpdate(this, infoflags, x, y, width, height); + } + +// notifyAll(); + } + + private void forceToIntARGB(){ + + int w = raster.getWidth(); + int h = raster.getHeight(); + + WritableRaster destRaster = rgbCM.createCompatibleWritableRaster(w, h); + + Object obj = null; + int pixels[] = new int[w]; + + if(cm instanceof IndexColorModel){ + IndexColorModel icm = (IndexColorModel) cm; + int colorMap[] = new int[icm.getMapSize()]; + icm.getRGBs(colorMap); + + for (int y = 0; y < h; y++) { + obj = raster.getDataElements(0, y, w, 1, obj); + byte ba[] = (byte[]) obj; + for (int x = 0; x < ba.length; x++) { + pixels[x] = colorMap[ba[x] & 0xff]; + } + destRaster.setDataElements(0, y, w, 1, pixels); + } + + }else{ + for(int y = 0; y < h; y++){ + for(int x = 0; x < w; x++){ + obj = raster.getDataElements(x, y, obj); + pixels[x] = cm.getRGB(obj); + } + destRaster.setDataElements(0, y, w, 1, pixels); + } + } + + synchronized(this){ + if(imageSurf != null){ + imageSurf.dispose(); + imageSurf = null; + } + if(image != null){ + image.flush(); + image = null; + } + cm = rgbCM; + raster = destRaster; + isIntRGB = true; + } + } + + public ImageSurface getImageSurface() { + if (imageSurf == null) { + ColorModel model = getColorModel(); + WritableRaster wr = getRaster(); + if(model != null && wr != null) { + imageSurf = new ImageSurface(model, wr); + } + } + return imageSurf; + } +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/image/OrdinaryWritableRaster.java b/app/src/main/java/org/apache/harmony/awt/gl/image/OrdinaryWritableRaster.java new file mode 100644 index 000000000..1748e1bdd --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/image/OrdinaryWritableRaster.java @@ -0,0 +1,153 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +/* + * Created on 30.09.2004 + * + */ +package org.apache.harmony.awt.gl.image; + +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.image.DataBuffer; +import java.awt.image.Raster; +import java.awt.image.SampleModel; +import java.awt.image.WritableRaster; + +public class OrdinaryWritableRaster extends WritableRaster { + + public OrdinaryWritableRaster(SampleModel sampleModel, + DataBuffer dataBuffer, Rectangle aRegion, + Point sampleModelTranslate, WritableRaster parent) { + super(sampleModel, dataBuffer, aRegion, sampleModelTranslate, parent); + } + + public OrdinaryWritableRaster(SampleModel sampleModel, + DataBuffer dataBuffer, Point origin) { + super(sampleModel, dataBuffer, origin); + } + + public OrdinaryWritableRaster(SampleModel sampleModel, Point origin) { + super(sampleModel, origin); + } + + @Override + public void setDataElements(int x, int y, Object inData) { + super.setDataElements(x, y, inData); + } + + @Override + public void setDataElements(int x, int y, int w, int h, Object inData) { + super.setDataElements(x, y, w, h, inData); + } + + @Override + public WritableRaster createWritableChild(int parentX, int parentY, int w, + int h, int childMinX, int childMinY, int[] bandList) { + return super.createWritableChild(parentX, parentY, w, h, childMinX, + childMinY, bandList); + } + + @Override + public WritableRaster createWritableTranslatedChild(int childMinX, + int childMinY) { + return super.createWritableTranslatedChild(childMinX, childMinY); + } + + @Override + public WritableRaster getWritableParent() { + return super.getWritableParent(); + } + + @Override + public void setRect(Raster srcRaster) { + super.setRect(srcRaster); + } + + @Override + public void setRect(int dx, int dy, Raster srcRaster) { + super.setRect(dx, dy, srcRaster); + } + + @Override + public void setDataElements(int x, int y, Raster inRaster) { + super.setDataElements(x, y, inRaster); + } + + @Override + public void setPixel(int x, int y, int[] iArray) { + super.setPixel(x, y, iArray); + } + + @Override + public void setPixel(int x, int y, float[] fArray) { + super.setPixel(x, y, fArray); + } + + @Override + public void setPixel(int x, int y, double[] dArray) { + super.setPixel(x, y, dArray); + } + + @Override + public void setPixels(int x, int y, int w, int h, int[] iArray) { + super.setPixels(x, y, w, h, iArray); + } + + @Override + public void setPixels(int x, int y, int w, int h, float[] fArray) { + super.setPixels(x, y, w, h, fArray); + } + + @Override + public void setPixels(int x, int y, int w, int h, double[] dArray) { + super.setPixels(x, y, w, h, dArray); + } + + @Override + public void setSamples(int x, int y, int w, int h, int b, int[] iArray) { + super.setSamples(x, y, w, h, b, iArray); + } + + @Override + public void setSamples(int x, int y, int w, int h, int b, float[] fArray) { + super.setSamples(x, y, w, h, b, fArray); + } + + @Override + public void setSamples(int x, int y, int w, int h, int b, double[] dArray) { + super.setSamples(x, y, w, h, b, dArray); + } + + @Override + public void setSample(int x, int y, int b, int s) { + super.setSample(x, y, b, s); + } + + @Override + public void setSample(int x, int y, int b, float s) { + super.setSample(x, y, b, s); + } + + @Override + public void setSample(int x, int y, int b, double s) { + super.setSample(x, y, b, s); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/apache/harmony/awt/gl/image/PngDecoder.java b/app/src/main/java/org/apache/harmony/awt/gl/image/PngDecoder.java new file mode 100644 index 000000000..7e85600ac --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/image/PngDecoder.java @@ -0,0 +1,270 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + * + * @date: Jul 22, 2005 + */ + +package org.apache.harmony.awt.gl.image; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Hashtable; +import java.awt.color.ColorSpace; +import java.awt.image.*; +import java.awt.*; + +import org.apache.harmony.awt.internal.nls.Messages; + +public class PngDecoder extends ImageDecoder { + // initializes proper field IDs + private static native void initIDs(); + + static { + System.loadLibrary("gl"); //$NON-NLS-1$ + initIDs(); + } + + private static final int hintflags = + ImageConsumer.SINGLEFRAME | // PNG is a static image + ImageConsumer.TOPDOWNLEFTRIGHT | // This order is only one possible + ImageConsumer.COMPLETESCANLINES; // Don't deliver incomplete scanlines + + // Each pixel is a grayscale sample. + private static final int PNG_COLOR_TYPE_GRAY = 0; + // Each pixel is an R,G,B triple. + private static final int PNG_COLOR_TYPE_RGB = 2; + // Each pixel is a palette index, a PLTE chunk must appear. + private static final int PNG_COLOR_TYPE_PLTE = 3; + // Each pixel is a grayscale sample, followed by an alpha sample. + private static final int PNG_COLOR_TYPE_GRAY_ALPHA = 4; + // Each pixel is an R,G,B triple, followed by an alpha sample. + private static final int PNG_COLOR_TYPE_RGBA = 6; + + private static final int INPUT_BUFFER_SIZE = 4096; + private byte buffer[] = new byte[INPUT_BUFFER_SIZE]; + + // Buffers for decoded image data + byte byteOut[]; + int intOut[]; + + // Native pointer to png decoder data + private long hNativeDecoder; + + int imageWidth, imageHeight; + int colorType; + int bitDepth; + byte cmap[]; + + boolean transferInts; // Is transfer type int?.. or byte? + int dataElementsPerPixel = 1; + + ColorModel cm; + + int updateFromScanline; // First scanline to update + int numScanlines; // Number of scanlines to update + + private native long decode(byte[] input, int bytesInBuffer, long hDecoder); + + private static native void releaseNativeDecoder(long hDecoder); + + public PngDecoder(DecodingImageSource src, InputStream is) { + super(src, is); + } + + @Override + public void decodeImage() throws IOException { + try { + int bytesRead = 0; + int needBytes, offset, bytesInBuffer = 0; + // Read from the input stream + for (;;) { + needBytes = INPUT_BUFFER_SIZE - bytesInBuffer; + offset = bytesInBuffer; + + bytesRead = inputStream.read(buffer, offset, needBytes); + + if (bytesRead < 0) { // Break, nothing to read from buffer, image truncated? + releaseNativeDecoder(hNativeDecoder); + break; + } + + // Keep track on how much bytes left in buffer + bytesInBuffer += bytesRead; + hNativeDecoder = decode(buffer, bytesInBuffer, hNativeDecoder); + // PNG decoder always consumes all bytes at once + bytesInBuffer = 0; + + // if (bytesConsumed < 0) + //break; // Error exit + + returnData(); + + // OK, we decoded all the picture in the right way... + if (hNativeDecoder == 0) { + break; + } + } + + imageComplete(ImageConsumer.STATICIMAGEDONE); + } catch (IOException e) { + throw e; + } catch (RuntimeException e) { + imageComplete(ImageConsumer.IMAGEERROR); + throw e; + } finally { + closeStream(); + } + } + + @SuppressWarnings("unused") + private void returnHeader() { // Called from native code + setDimensions(imageWidth, imageHeight); + + switch (colorType) { + case PNG_COLOR_TYPE_GRAY: { + if (bitDepth != 8 && bitDepth != 4 && bitDepth != 2 && bitDepth != 1) { + // awt.3C=Unknown PNG color type + throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$ + } + + // Create gray color model + int numEntries = 1 << bitDepth; + int scaleFactor = 255 / (numEntries-1); + byte comps[] = new byte[numEntries]; + for (int i = 0; i < numEntries; i++) { + comps[i] = (byte) (i * scaleFactor); + } + cm = new IndexColorModel(/*bitDepth*/8, numEntries, comps, comps, comps); + + transferInts = false; + break; + } + + case PNG_COLOR_TYPE_RGB: { + if (bitDepth != 8) { + // awt.3C=Unknown PNG color type + throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$ + } + + cm = new DirectColorModel(24, 0xFF0000, 0xFF00, 0xFF); + + transferInts = true; + break; + } + + case PNG_COLOR_TYPE_PLTE: { + if (bitDepth != 8 && bitDepth != 4 && bitDepth != 2 && bitDepth != 1) { + // awt.3C=Unknown PNG color type + throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$ + } + + cm = new IndexColorModel(/*bitDepth*/8, cmap.length / 3, cmap, 0, false); + + transferInts = false; + break; + } + + case PNG_COLOR_TYPE_GRAY_ALPHA: { + if (bitDepth != 8) { + // awt.3C=Unknown PNG color type + throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$ + } + + cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY), + true, false, + Transparency.TRANSLUCENT, + DataBuffer.TYPE_BYTE); + + transferInts = false; + dataElementsPerPixel = 2; + break; + } + + case PNG_COLOR_TYPE_RGBA: { + if (bitDepth != 8) { + // awt.3C=Unknown PNG color type + throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$ + } + + cm = ColorModel.getRGBdefault(); + + transferInts = true; + break; + } + default: + // awt.3C=Unknown PNG color type + throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$ + } + + // Create output buffer + if (transferInts) { + intOut = new int[imageWidth * imageHeight]; + } else { + byteOut = new byte[imageWidth * imageHeight * dataElementsPerPixel]; + } + + setColorModel(cm); + + setHints(hintflags); + setProperties(new Hashtable()); // Empty + } + + // Send the data to the consumer + private void returnData() { + // Send 1 or more scanlines to the consumer. + if (numScanlines > 0) { + // Native decoder could have returned + // some data from the next pass, handle it here + int pass1, pass2; + if (updateFromScanline + numScanlines > imageHeight) { + pass1 = imageHeight - updateFromScanline; + pass2 = updateFromScanline + numScanlines - imageHeight; + } else { + pass1 = numScanlines; + pass2 = 0; + } + + transfer(updateFromScanline, pass1); + if (pass2 != 0) { + transfer(0, pass2); + } + } + } + + private void transfer(int updateFromScanline, int numScanlines) { + if (transferInts) { + setPixels( + 0, updateFromScanline, + imageWidth, numScanlines, + cm, intOut, + updateFromScanline * imageWidth, + imageWidth + ); + } else { + setPixels( + 0, updateFromScanline, + imageWidth, numScanlines, + cm, byteOut, + updateFromScanline * imageWidth * dataElementsPerPixel, + imageWidth * dataElementsPerPixel + ); + } + } +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/image/PngDecoderJava.java b/app/src/main/java/org/apache/harmony/awt/gl/image/PngDecoderJava.java new file mode 100644 index 000000000..512ce4ea2 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/image/PngDecoderJava.java @@ -0,0 +1,298 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.awt.gl.image; + +// A simple PNG decoder source code in Java. +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; +import java.awt.image.IndexColorModel; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.util.zip.CRC32; +import java.util.zip.InflaterInputStream; + +//import javax.swing.JFrame; + +public class PngDecoderJava { + +/* + public static void main(String[] args) throws Exception { + String name = "logo.png"; + if (args.length > 0) + name = args[0]; + InputStream in = PngDecoderJava.class.getResourceAsStream(name); + final BufferedImage image = PngDecoderJava.decode(in); + in.close(); + + JFrame f = new JFrame() { + public void paint(Graphics g) { + Insets insets = getInsets(); + g.drawImage(image, insets.left, insets.top, null); + } + }; + f.setVisible(true); + Insets insets = f.getInsets(); + f.setSize(image.getWidth() + insets.left + insets.right, image + .getHeight() + + insets.top + insets.bottom); + } + */ + + public static BufferedImage decode(InputStream in) throws IOException { + DataInputStream dataIn = new DataInputStream(in); + readSignature(dataIn); + PNGData chunks = readChunks(dataIn); + + long widthLong = chunks.getWidth(); + long heightLong = chunks.getHeight(); + if (widthLong > Integer.MAX_VALUE || heightLong > Integer.MAX_VALUE) + throw new IOException("That image is too wide or tall."); + int width = (int) widthLong; + int height = (int) heightLong; + + ColorModel cm = chunks.getColorModel(); + WritableRaster raster = chunks.getRaster(); + + BufferedImage image = new BufferedImage(cm, raster, false, null); + + return image; + } + + protected static void readSignature(DataInputStream in) throws IOException { + long signature = in.readLong(); + if (signature != 0x89504e470d0a1a0aL) + throw new IOException("PNG signature not found!"); + } + + protected static PNGData readChunks(DataInputStream in) throws IOException { + PNGData chunks = new PNGData(); + + boolean trucking = true; + while (trucking) { + try { + // Read the length. + int length = in.readInt(); + if (length < 0) + throw new IOException("Sorry, that file is too long."); + // Read the type. + byte[] typeBytes = new byte[4]; + in.readFully(typeBytes); + // Read the data. + byte[] data = new byte[length]; + in.readFully(data); + // Read the CRC. + long crc = in.readInt() & 0x00000000ffffffffL; // Make it + // unsigned. + if (verifyCRC(typeBytes, data, crc) == false) + throw new IOException("That file appears to be corrupted."); + + PNGChunk chunk = new PNGChunk(typeBytes, data); + chunks.add(chunk); + } catch (EOFException eofe) { + trucking = false; + } + } + return chunks; + } + + protected static boolean verifyCRC(byte[] typeBytes, byte[] data, long crc) { + CRC32 crc32 = new CRC32(); + crc32.update(typeBytes); + crc32.update(data); + long calculated = crc32.getValue(); + return (calculated == crc); + } +} + +class PNGData { + private int mNumberOfChunks; + + private PNGChunk[] mChunks; + + public PNGData() { + mNumberOfChunks = 0; + mChunks = new PNGChunk[10]; + } + + public void add(PNGChunk chunk) { + mChunks[mNumberOfChunks++] = chunk; + if (mNumberOfChunks >= mChunks.length) { + PNGChunk[] largerArray = new PNGChunk[mChunks.length + 10]; + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(mChunks, 0, largerArray, 0, mChunks.length); + mChunks = largerArray; + } + } + + public long getWidth() { + return getChunk("IHDR").getUnsignedInt(0); + } + + public long getHeight() { return getChunk("IHDR").getUnsignedInt(4); + } + + public short getBitsPerPixel() { + return getChunk("IHDR").getUnsignedByte(8); + } + + public short getColorType() { + return getChunk("IHDR").getUnsignedByte(9); + } + + public short getCompression() { + return getChunk("IHDR").getUnsignedByte(10); + } + + public short getFilter() { + return getChunk("IHDR").getUnsignedByte(11); + } + + public short getInterlace() { + return getChunk("IHDR").getUnsignedByte(12); + } + + public ColorModel getColorModel() { + short colorType = getColorType(); + int bitsPerPixel = getBitsPerPixel(); + + if (colorType == 3) { + byte[] paletteData = getChunk("PLTE").getData(); + int paletteLength = paletteData.length / 3; + return new IndexColorModel(bitsPerPixel, paletteLength, + paletteData, 0, false); + } + System.out.println("Unsupported color type: " + colorType); + return null; + } + + public WritableRaster getRaster() { + int width = (int) getWidth(); + int height = (int) getHeight(); + int bitsPerPixel = getBitsPerPixel(); + short colorType = getColorType(); + + if (colorType == 3) { + byte[] imageData = getImageData(); + //Orig: DataBuffer db = new DataBufferByte(imageData, imageData.length); + int len = Math.max(imageData.length, (width - 1) * (height -1)); + DataBuffer db = new DataBufferByte(imageData, len); + WritableRaster raster = Raster.createPackedRaster(db, width, + height, bitsPerPixel, null); + return raster; + } else + System.out.println("Unsupported color type!"); + return null; + } + + public byte[] getImageData() { + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + // Write all the IDAT data into the array. + for (int i = 0; i < mNumberOfChunks; i++) { + PNGChunk chunk = mChunks[i]; + if (chunk.getTypeString().equals("IDAT")) { + out.write(chunk.getData()); + } + } + out.flush(); + // Now deflate the data. + InflaterInputStream in = new InflaterInputStream( + new ByteArrayInputStream(out.toByteArray())); + ByteArrayOutputStream inflatedOut = new ByteArrayOutputStream(); + int readLength; + byte[] block = new byte[8192]; + while ((readLength = in.read(block)) != -1) + inflatedOut.write(block, 0, readLength); + inflatedOut.flush(); + byte[] imageData = inflatedOut.toByteArray(); + // Compute the real length. + int width = (int) getWidth(); + int height = (int) getHeight(); + int bitsPerPixel = getBitsPerPixel(); + int length = width * height * bitsPerPixel / 8; + + byte[] prunedData = new byte[length]; + + // We can only deal with non-interlaced images. + if (getInterlace() == 0) { + int index = 0; + for (int i = 0; i < length; i++) { + if ((i * 8 / bitsPerPixel) % width == 0) { + index++; // Skip the filter byte. + } + prunedData[i] = imageData[index++]; + } + } else + System.out.println("Couldn't undo interlacing."); + + return prunedData; + } catch (IOException ioe) { + } + return null; + } + + public PNGChunk getChunk(String type) { + for (int i = 0; i < mNumberOfChunks; i++) + if (mChunks[i].getTypeString().equals(type)) + return mChunks[i]; + return null; + } +} + +class PNGChunk { + private byte[] mType; + + private byte[] mData; + + public PNGChunk(byte[] type, byte[] data) { + mType = type; + mData = data; + } + + public String getTypeString() { + try { + return new String(mType, "UTF8"); + } catch (UnsupportedEncodingException uee) { + return ""; + } + } + + public byte[] getData() { + return mData; + } + + public long getUnsignedInt(int offset) { + long value = 0; + for (int i = 0; i < 4; i++) + value += (mData[offset + i] & 0xff) << ((3 - i) * 8); + return value; + } + + public short getUnsignedByte(int offset) { + return (short) (mData[offset] & 0x00ff); + } +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/image/URLDecodingImageSource.java b/app/src/main/java/org/apache/harmony/awt/gl/image/URLDecodingImageSource.java new file mode 100644 index 000000000..a1899d650 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/image/URLDecodingImageSource.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + */ +/* + * Created on 10.02.2005 + * + */ +package org.apache.harmony.awt.gl.image; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLConnection; +import java.security.Permission; + +public class URLDecodingImageSource extends DecodingImageSource { + + URL url; + + public URLDecodingImageSource(URL url){ + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkConnect(url.getHost(), url.getPort()); + try { + Permission p = url.openConnection().getPermission(); + security.checkPermission(p); + } catch (IOException e) { + } + } + this.url = url; + } + + @Override + protected boolean checkConnection() { + SecurityManager security = System.getSecurityManager(); + if (security != null) { + try { + security.checkConnect(url.getHost(), url.getPort()); + return true; + } catch (SecurityException e) { + return false; + } + } + return true; + } + + @Override + protected InputStream getInputStream() { + try{ + URLConnection uc = url.openConnection(); + // BEGIN android-modified + return new BufferedInputStream(uc.getInputStream(), 8192); + // END android-modified + }catch(IOException e){ + return null; + } + } + +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/render/Blitter.java b/app/src/main/java/org/apache/harmony/awt/gl/render/Blitter.java new file mode 100644 index 000000000..3b8012e72 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/render/Blitter.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + * Created on 14.11.2005 + * + */ +package org.apache.harmony.awt.gl.render; + +import java.awt.Color; +import java.awt.Composite; +import java.awt.geom.AffineTransform; + +import org.apache.harmony.awt.gl.MultiRectArea; +import org.apache.harmony.awt.gl.Surface; + +/** + * The interface for objects which can drawing Images on other Images which have + * Graphics or on the display. + */ +public interface Blitter { + + public abstract void blit(int srcX, int srcY, Surface srcSurf, + int dstX, int dstY, Surface dstSurf, int width, int height, + AffineTransform sysxform, AffineTransform xform, + Composite comp, Color bgcolor, + MultiRectArea clip); + + public abstract void blit(int srcX, int srcY, Surface srcSurf, + int dstX, int dstY, Surface dstSurf, int width, int height, + AffineTransform sysxform, Composite comp, Color bgcolor, + MultiRectArea clip); + + public abstract void blit(int srcX, int srcY, Surface srcSurf, + int dstX, int dstY, Surface dstSurf, int width, int height, + Composite comp, Color bgcolor, MultiRectArea clip); + +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/render/JavaArcRasterizer.java b/app/src/main/java/org/apache/harmony/awt/gl/render/JavaArcRasterizer.java new file mode 100644 index 000000000..b643b41ac --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/render/JavaArcRasterizer.java @@ -0,0 +1,502 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Denis M. Kishenko + * @version $Revision$ + */ +package org.apache.harmony.awt.gl.render; + +import org.apache.harmony.awt.gl.MultiRectArea; + +public class JavaArcRasterizer { + + /** + * Adds particular arc segment to mra + */ + static void addX0LineSeg(MultiRectArea mra, int[] line, int cx, int cy, int b, int start, int finish) { + int x1 = 0; + for(int i = 0; i < line.length; i++) { + int x2 = line[i]; + int y = cy + (b - i); + if (x1 <= finish && x2 >= start) { + mra.addRect(cx + Math.max(x1, start), y, cx + Math.min(x2, finish), y); + } + x1 = x2 + 1; + } + } + + static void addX1LineSeg(MultiRectArea mra, int[] line, int cx, int cy, int b, int start, int finish) { + int x1 = 0; + for(int i = 0; i < line.length; i++) { + int x2 = line[i]; + int y = cy - (b - i); + if (x1 <= finish && x2 >= start) { + mra.addRect(cx + Math.max(x1, start), y, cx + Math.min(x2, finish), y); + } + x1 = x2 + 1; + } + } + + static void addX2LineSeg(MultiRectArea mra, int[] line, int cx, int cy, int b, int start, int finish) { + int x1 = 0; + for(int i = 0; i < line.length; i++) { + int x2 = line[i]; + int y = cy - (b - i); + if (x1 <= finish && x2 >= start) { + mra.addRect(cx - Math.min(x2, finish), y, cx - Math.max(x1, start), y); + } + x1 = x2 + 1; + } + } + + static void addX3LineSeg(MultiRectArea mra, int[] line, int cx, int cy, int b, int start, int finish) { + int x1 = 0; + for(int i = 0; i < line.length; i++) { + int x2 = line[i]; + int y = cy + (b - i); + if (x1 <= finish && x2 >= start) { + mra.addRect(cx - Math.min(x2, finish), y, cx - Math.max(x1, start), y); + } + x1 = x2 + 1; + } + } + + static void addY0LineSeg(MultiRectArea mra, int[] line, int cx, int cy, int b, int start, int finish) { + int y1 = 0; + for(int i = 0; i < line.length; i++) { + int x = cx + (b - i); + int y2 = line[i]; + if (y1 <= finish && y2 >= start) { + mra.addRect(x, cy + Math.max(y1, start), x, cy + Math.min(y2, finish)); + } + y1 = y2 + 1; + } + } + + static void addY1LineSeg(MultiRectArea mra, int[] line, int cx, int cy, int b, int start, int finish) { + int y1 = 0; + for(int i = 0; i < line.length; i++) { + int x = cx - (b - i); + int y2 = line[i]; + if (y1 <= finish && y2 >= start) { + mra.addRect(x, cy + Math.max(y1, start), x, cy + Math.min(y2, finish)); + } + y1 = y2 + 1; + } + } + + static void addY2LineSeg(MultiRectArea mra, int[] line, int cx, int cy, int b, int start, int finish) { + int y1 = 0; + for(int i = 0; i < line.length; i++) { + int x = cx - (b - i); + int y2 = line[i]; + if (y1 <= finish && y2 >= start) { + mra.addRect(x, cy - Math.min(y2, finish), x, cy - Math.max(y1, start)); + } + y1 = y2 + 1; + } + } + + static void addY3LineSeg(MultiRectArea mra, int[] line, int cx, int cy, int b, int start, int finish) { + int y1 = 0; + for(int i = 0; i < line.length; i++) { + int x = cx + (b - i); + int y2 = line[i]; + if (y1 <= finish && y2 >= start) { + mra.addRect(x, cy - Math.min(y2, finish), x, cy - Math.max(y1, start)); + } + y1 = y2 + 1; + } + } + + static void addX0Line(MultiRectArea mra, int[] line, int cx, int cy, int b) { + int prev = 0; + for(int i = 0; i < line.length; i++) { + mra.addRect(cx + prev, cy + (b - i), cx + line[i], cy + (b - i)); + prev = line[i] + 1; + } + } + + static void addX1Line(MultiRectArea mra, int[] line, int cx, int cy, int b) { + int prev = 0; + for(int i = 0; i < line.length; i++) { + mra.addRect(cx + prev, cy - (b - i), cx + line[i], cy - (b - i)); + prev = line[i] + 1; + } + } + + static void addX2Line(MultiRectArea mra, int[] line, int cx, int cy, int b) { + int prev = 0; + for(int i = 0; i < line.length; i++) { + mra.addRect(cx - line[i], cy - (b - i), cx - prev, cy - (b - i)); + prev = line[i] + 1; + } + } + + static void addX3Line(MultiRectArea mra, int[] line, int cx, int cy, int b) { + int prev = 0; + for(int i = 0; i < line.length; i++) { + mra.addRect(cx - line[i], cy + (b - i), cx - prev, cy + (b - i)); + prev = line[i] + 1; + } + } + + static void addY0Line(MultiRectArea mra, int[] line, int cx, int cy, int a) { + int prev = 0; + for(int i = 0; i < line.length; i++) { + mra.addRect(cx + (a - i), cy + prev, cx + (a - i), cy + line[i]); + prev = line[i] + 1; + } + } + + static void addY1Line(MultiRectArea mra, int[] line, int cx, int cy, int a) { + int prev = 0; + for(int i = 0; i < line.length; i++) { + mra.addRect(cx - (a - i), cy + prev, cx - (a - i), cy + line[i]); + prev = line[i] + 1; + } + } + + static void addY2Line(MultiRectArea mra, int[] line, int cx, int cy, int a) { + int prev = 0; + for(int i = 0; i < line.length; i++) { + mra.addRect(cx - (a - i), cy - line[i], cx - (a - i), cy - prev); + prev = line[i] + 1; + } + } + + static void addY3Line(MultiRectArea mra, int[] line, int cx, int cy, int a) { + int prev = 0; + for(int i = 0; i < line.length; i++) { + mra.addRect(cx + (a - i), cy - line[i], cx + (a - i), cy - prev); + prev = line[i] + 1; + } + } + + /** + * Returns normalized angle (from 0 to 360 degrees) + */ + static double getNormAngle(double angle) { + angle -= Math.floor(angle / 360) * 360; + if (angle < 0) { + angle += 360; + } + return angle; + } + + /** + * Creates arc lookup table + */ + static int[] createLine(int a, int b, int xcount, int ycount) { + int[] buf = new int[b - ycount + 1]; + int d = a * a + 2 * b * b - 2 * a * a * b; + int x = 0; + int y = b; + while (y >= ycount) { + if (d < 0) { + d = d + b * b * (4 * x + 6); + } else { + buf[b - y] = x; + d = d + b * b * (4 * x + 6) + 4 * a * a * (1 - y); + y--; + } + x++; + } + return buf; + } + + /** + * Adds head/tail arc segment to MultiRectArea + */ + static void addSeg(MultiRectArea mra, int cx1, int cy1, int cx2, int cy2, int a, int b, int[] xline, int[] yline, int[] bounds) { + switch(bounds[0]) { + case 0: + addY3LineSeg(mra, yline, cx2, cy1, a, bounds[1], bounds[2]); + break; + case 1: + addX1LineSeg(mra, xline, cx2, cy1, b, bounds[1], bounds[2]); + break; + case 2: + addX2LineSeg(mra, xline, cx1, cy1, b, bounds[1], bounds[2]); + break; + case 3: + addY2LineSeg(mra, yline, cx1, cy1, a, bounds[1], bounds[2]); + break; + case 4: + addY1LineSeg(mra, yline, cx1, cy2, a, bounds[1], bounds[2]); + break; + case 5: + addX3LineSeg(mra, xline, cx1, cy2, b, bounds[1], bounds[2]); + break; + case 6: + addX0LineSeg(mra, xline, cx2, cy2, b, bounds[1], bounds[2]); + break; + case 7: + addY0LineSeg(mra, yline, cx2, cy2, a, bounds[1], bounds[2]); + break; + } + } + + /** + * Returns bounds for non quadratic arc head + */ + static int[] getSegment1(double angle, int ax, int ay, int xcount, int ycount) { + int[] bounds = new int[3]; + switch((int)(angle / 90)) { + case 0: + if (xcount < ax) { + bounds[0] = 0; // Y3 + bounds[1] = -ay; + bounds[2] = ycount; + } else { + bounds[0] = 1; // X1 + bounds[1] = 0; + bounds[2] = ax; + } + break; + case 1: + if (xcount > -ax) { + bounds[0] = 2; // X2 + bounds[1] = -ax; + bounds[2] = xcount; + } else { + bounds[0] = 3; // Y2 + bounds[1] = 0; + bounds[2] = -ay; + } + break; + case 2: + if (xcount < -ax) { + bounds[0] = 4; // Y1 + bounds[1] = ay; + bounds[2] = ycount; + } else { + bounds[0] = 5; // X3 + bounds[1] = 0; + bounds[2] = -ax; + } + break; + case 3: + if (xcount > ax) { + bounds[0] = 6; // X0 + bounds[1] = ax; + bounds[2] = xcount; + } else { + bounds[0] = 7; // Y0 + bounds[1] = 0; + bounds[2] = ay; + } + break; + } + return bounds; + } + + /** + * Returns bounds for non quadratic arc tail + */ + static int[] getSegment2(double angle, int ax, int ay, int xcount, int ycount) { + int[] bounds = new int[3]; + switch((int)(angle / 90)) { + case 0: + if (xcount < ax) { + bounds[0] = 0; // Y3 + bounds[1] = 0; + bounds[2] = -ay; + } else { + bounds[0] = 1; // X1 + bounds[1] = ax; + bounds[2] = xcount; + } + break; + case 1: + if (xcount > -ax) { + bounds[0] = 2; // X2 + bounds[1] = 0; + bounds[2] = -ax; + } else { + bounds[0] = 3; // Y2 + bounds[1] = -ay; + bounds[2] = ycount; + } + break; + case 2: + if (xcount < -ax) { + bounds[0] = 4; // Y1 + bounds[1] = 0; + bounds[2] = ay; + } else { + bounds[0] = 5; // X3 + bounds[1] = -ax; + bounds[2] = xcount; + } + break; + case 3: + if (xcount > ax) { + bounds[0] = 6; // X0 + bounds[1] = 0; + bounds[2] = ax; + } else { + bounds[0] = 7; // Y0 + bounds[1] = ay; + bounds[2] = ycount; + } + break; + } + return bounds; + } + + /** + * Rasterizes arc using clippind and dashing style + * @param x1 - the x coordinate of the left-upper corner of the arc bounds + * @param y1 - the y coordinate of the left-upper corner of the arc bounds + * @param width - the width of the arc bounds + * @param height - the height of the arc bounds + * @param angleStart - the start angle of the arc in degrees + * @param angleExtent - the angle extent in degrees + * @param clip - the MultiRectArea object of clipping area + * @return a MultiRectArea of rasterizer arc + */ + public static MultiRectArea rasterize(int x, int y, int width, int height, double angleStart, double angleExtent, MultiRectArea clip) { + + MultiRectArea mra = new MultiRectArea(false); + + int cx1, cx2, cy1, cy2; + cx1 = cx2 = x + width / 2; + cy1 = cy2 = y + height / 2; + + if (width % 2 == 0) { + cx2--; + } + + if (height % 2 == 0) { + cy2--; + } + + int a = width / 2; + int b = height / 2; + double c = Math.sqrt(a * a + b * b); + + int xcount, ycount; + if (a < b) { + xcount = (int)Math.ceil(a * a / c); + ycount = (int)Math.floor(b * b / c); + } else { + xcount = (int)Math.floor(a * a / c); + ycount = (int)Math.ceil(b * b / c); + } + + int[] xline = createLine(a, b, xcount, ycount); + int[] yline = createLine(b, a, ycount, xcount); + + // Correct lines + int i = xline.length; + while(xline[--i] > xcount) { + xline[i] = xcount; + } + + i = yline.length; + while(yline[--i] > ycount) { + yline[i] = ycount; + } + + if (Math.abs(angleExtent) >= 360) { + // Rasterize CIRCLE + addX0Line(mra, xline, cx2, cy2, b); + addX1Line(mra, xline, cx2, cy1, b); + addX2Line(mra, xline, cx1, cy1, b); + addX3Line(mra, xline, cx1, cy2, b); + addY0Line(mra, yline, cx2, cy2, a); + addY1Line(mra, yline, cx1, cy2, a); + addY2Line(mra, yline, cx1, cy1, a); + addY3Line(mra, yline, cx2, cy1, a); + } else { + // Rasterize ARC + angleStart = getNormAngle(angleStart); + double angleFinish = getNormAngle(angleStart + angleExtent); + + if (angleExtent < 0) { + double tmp = angleStart; + angleStart = angleFinish; + angleFinish = tmp; + } + + double radStart = -Math.toRadians(angleStart); + double radFinish = -Math.toRadians(angleFinish); + int ax1 = (int)(a * Math.cos(radStart)); + int ay1 = (int)(b * Math.sin(radStart)); + int ax2 = (int)(a * Math.cos(radFinish)); + int ay2 = (int)(b * Math.sin(radFinish)); + + int[] seg1 = getSegment1(angleStart, ax1, ay1, xcount, ycount); + int[] seg2 = getSegment2(angleFinish, ax2, ay2, xcount, ycount); + + // Start and Finish located in the same quater + if (angleStart < angleFinish && seg1[0] == seg2[0]) { + if (seg1[0] % 2 == 0) { + seg1[2] = seg2[2]; + } else { + seg1[1] = seg2[1]; + } + addSeg(mra, cx1, cy1, cx2, cy2, a, b, xline, yline, seg1); + return mra; + } + + addSeg(mra, cx1, cy1, cx2, cy2, a, b, xline, yline, seg1); + addSeg(mra, cx1, cy1, cx2, cy2, a, b, xline, yline, seg2); + + int startSeg = (seg1[0] + 1) % 8; + int finishSeg = seg2[0]; + + while (startSeg != finishSeg) { + switch(startSeg) { + case 0: + addY3Line(mra, yline, cx2, cy1, a); + break; + case 1: + addX1Line(mra, xline, cx2, cy1, b); + break; + case 2: + addX2Line(mra, xline, cx1, cy1, b); + break; + case 3: + addY2Line(mra, yline, cx1, cy1, a); + break; + case 4: + addY1Line(mra, yline, cx1, cy2, a); + break; + case 5: + addX3Line(mra, xline, cx1, cy2, b); + break; + case 6: + addX0Line(mra, xline, cx2, cy2, b); + break; + case 7: + addY0Line(mra, yline, cx2, cy2, a); + break; + } + startSeg = (startSeg + 1) % 8; + } + } + + if (clip != null) { + mra.intersect(clip); + } + + return mra; + } + +} \ No newline at end of file diff --git a/app/src/main/java/org/apache/harmony/awt/gl/render/JavaBlitter.java b/app/src/main/java/org/apache/harmony/awt/gl/render/JavaBlitter.java new file mode 100644 index 000000000..67e0a59b7 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/render/JavaBlitter.java @@ -0,0 +1,611 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Igor V. Stolyarov + * @version $Revision$ + * Created on 18.11.2005 + * + */ +package org.apache.harmony.awt.gl.render; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.CompositeContext; +import java.awt.Rectangle; +import java.awt.geom.AffineTransform; +import java.awt.geom.NoninvertibleTransformException; +import java.awt.geom.Rectangle2D; +import java.awt.image.ColorModel; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; + +import org.apache.harmony.awt.gl.MultiRectArea; +import org.apache.harmony.awt.gl.Surface; +import org.apache.harmony.awt.gl.XORComposite; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * Java implenetation of the Blitter interface. Using when we can't + * draw images natively. + */ +public class JavaBlitter implements Blitter { + + /** + * Instead of multiplication and division we are using values from + * Lookup tables. + */ + static byte mulLUT[][]; // Lookup table for multiplication + static byte divLUT[][]; // Lookup table for division + + static{ + mulLUT = new byte[256][256]; + for(int i = 0; i < 256; i++){ + for(int j = 0; j < 256; j++){ + mulLUT[i][j] = (byte)((float)(i * j)/255 + 0.5f); + } + } + divLUT = new byte[256][256]; + for(int i = 1; i < 256; i++){ + for(int j = 0; j < i; j++){ + divLUT[i][j] = (byte)(((float)j / 255) / ((float)i/ 255) * 255 + 0.5f); + } + for(int j = i; j < 256; j++){ + divLUT[i][j] = (byte)255; + } + } + } + + final static int AlphaCompositeMode = 1; + final static int XORMode = 2; + + final static JavaBlitter inst = new JavaBlitter(); + + public static JavaBlitter getInstance(){ + return inst; + } + + public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY, + Surface dstSurf, int width, int height, AffineTransform sysxform, + AffineTransform xform, Composite comp, Color bgcolor, + MultiRectArea clip) { + + if(xform == null){ + blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, width, height, + sysxform, comp, bgcolor, clip); + }else{ + double scaleX = xform.getScaleX(); + double scaleY = xform.getScaleY(); + double scaledX = dstX / scaleX; + double scaledY = dstY / scaleY; + AffineTransform at = new AffineTransform(); + at.setToTranslation(scaledX, scaledY); + xform.concatenate(at); + sysxform.concatenate(xform); + blit(srcX, srcY, srcSurf, 0, 0, dstSurf, width, height, + sysxform, comp, bgcolor, clip); + } + + } + + public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY, + Surface dstSurf, int width, int height, AffineTransform sysxform, + Composite comp, Color bgcolor, MultiRectArea clip) { + + if(sysxform == null) { + sysxform = new AffineTransform(); + } + int type = sysxform.getType(); + switch(type){ + case AffineTransform.TYPE_TRANSLATION: + dstX += sysxform.getTranslateX(); + dstY += sysxform.getTranslateY(); + case AffineTransform.TYPE_IDENTITY: + blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, + width, height, comp, bgcolor, clip); + break; + default: + int srcW = srcSurf.getWidth(); + int srcH = srcSurf.getHeight(); + + int w = srcX + width < srcW ? width : srcW - srcX; + int h = srcY + height < srcH ? height : srcH - srcY; + + ColorModel srcCM = srcSurf.getColorModel(); + Raster srcR = srcSurf.getRaster().createChild(srcX, srcY, + w, h, 0, 0, null); + + ColorModel dstCM = dstSurf.getColorModel(); + WritableRaster dstR = dstSurf.getRaster(); + + transformedBlit(srcCM, srcR, 0, 0, dstCM, dstR, dstX, dstY, w, h, + sysxform, comp, bgcolor, clip); + + } + } + + public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY, + Surface dstSurf, int width, int height, Composite comp, + Color bgcolor, MultiRectArea clip) { + + javaBlt(srcX, srcY, srcSurf.getWidth(), srcSurf.getHeight(), + srcSurf.getColorModel(), srcSurf.getRaster(), dstX, dstY, + dstSurf.getWidth(), dstSurf.getHeight(), + dstSurf.getColorModel(), dstSurf.getRaster(), + width, height, comp, bgcolor, clip); + + } + public void javaBlt(int srcX, int srcY, int srcW, int srcH, + ColorModel srcCM, Raster srcRast, int dstX, int dstY, + int dstW, int dstH, ColorModel dstCM, WritableRaster dstRast, + int width, int height, Composite comp, Color bgcolor, + MultiRectArea clip){ + + int srcX2 = srcW - 1; + int srcY2 = srcH - 1; + int dstX2 = dstW - 1; + int dstY2 = dstH - 1; + + if(srcX < 0){ + width += srcX; + srcX = 0; + } + if(srcY < 0){ + height += srcY; + srcY = 0; + } + + if(dstX < 0){ + width += dstX; + srcX -= dstX; + dstX = 0; + } + if(dstY < 0){ + height += dstY; + srcY -= dstY; + dstY = 0; + } + + if(srcX > srcX2 || srcY > srcY2) { + return; + } + if(dstX > dstX2 || dstY > dstY2) { + return; + } + + if(srcX + width > srcX2) { + width = srcX2 - srcX + 1; + } + if(srcY + height > srcY2) { + height = srcY2 - srcY + 1; + } + if(dstX + width > dstX2) { + width = dstX2 - dstX + 1; + } + if(dstY + height > dstY2) { + height = dstY2 - dstY + 1; + } + + if(width <= 0 || height <= 0) { + return; + } + + int clipRects[]; + if(clip != null) { + clipRects = clip.rect; + } else { + clipRects = new int[]{5, 0, 0, dstW - 1, dstH - 1}; + } + + boolean isAlphaComp = false; + int rule = 0; + float alpha = 0; + boolean isXORComp = false; + Color xorcolor = null; + CompositeContext cont = null; + + if(comp instanceof AlphaComposite){ + isAlphaComp = true; + AlphaComposite ac = (AlphaComposite) comp; + rule = ac.getRule(); + alpha = ac.getAlpha(); + }else if(comp instanceof XORComposite){ + isXORComp = true; + XORComposite xcomp = (XORComposite) comp; + xorcolor = xcomp.getXORColor(); + }else{ + cont = comp.createContext(srcCM, dstCM, null); + } + + for(int i = 1; i < clipRects[0]; i += 4){ + int _sx = srcX; + int _sy = srcY; + + int _dx = dstX; + int _dy = dstY; + + int _w = width; + int _h = height; + + int cx = clipRects[i]; // Clipping left top X + int cy = clipRects[i + 1]; // Clipping left top Y + int cx2 = clipRects[i + 2]; // Clipping right bottom X + int cy2 = clipRects[i + 3]; // Clipping right bottom Y + + if(_dx > cx2 || _dy > cy2 || dstX2 < cx || dstY2 < cy) { + continue; + } + + if(cx > _dx){ + int shx = cx - _dx; + _w -= shx; + _dx = cx; + _sx += shx; + } + + if(cy > _dy){ + int shy = cy - _dy; + _h -= shy; + _dy = cy; + _sy += shy; + } + + if(_dx + _w > cx2 + 1){ + _w = cx2 - _dx + 1; + } + + if(_dy + _h > cy2 + 1){ + _h = cy2 - _dy + 1; + } + + if(_sx > srcX2 || _sy > srcY2) { + continue; + } + + if(isAlphaComp){ + alphaCompose(_sx, _sy, srcCM, srcRast, _dx, _dy, + dstCM, dstRast, _w, _h, rule, alpha, bgcolor); + }else if(isXORComp){ + xorCompose(_sx, _sy, srcCM, srcRast, _dx, _dy, + dstCM, dstRast, _w, _h, xorcolor); + }else{ + Raster sr = srcRast.createChild(_sx, _sy, _w, _h, 0, 0, null); + WritableRaster dr = dstRast.createWritableChild(_dx, _dy, + _w, _h, 0, 0, null); + cont.compose(sr, dr, dr); + } + } + } + + void alphaCompose(int srcX, int srcY, ColorModel srcCM, Raster srcRast, + int dstX, int dstY, ColorModel dstCM, WritableRaster dstRast, + int width, int height, int rule, float alpha, Color bgcolor){ + + Object srcPixel, dstPixel; + int srcConstAllpha = (int)(alpha * 255 + 0.5f); + int srcRGB, dstRGB = 0; + + if(bgcolor != null){ + dstRGB = bgcolor.getRGB(); + } + + for(int sy = srcY, dy = dstY, srcYMax = srcY + height; sy < srcYMax; sy++, dy++){ + for(int sx = srcX, dx = dstX, srcXMax = srcX + width; sx < srcXMax; sx++, dx++){ + srcPixel = srcRast.getDataElements(sx, sy, null); + srcRGB = srcCM.getRGB(srcPixel); + if(bgcolor == null){ + dstPixel = dstRast.getDataElements(dx, dy, null); + dstRGB = dstCM.getRGB(dstPixel); + } + + dstRGB = compose(srcRGB, srcCM.isAlphaPremultiplied(), + dstRGB, dstCM.hasAlpha(), dstCM.isAlphaPremultiplied(), + rule, srcConstAllpha); + + dstPixel = dstCM.getDataElements(dstRGB, null); + dstRast.setDataElements(dx,dy,dstPixel); + } + } + } + + void xorCompose(int srcX, int srcY, ColorModel srcCM, Raster srcRast, + int dstX, int dstY, ColorModel dstCM, WritableRaster dstRast, + int width, int height, Color xorcolor){ + + Object srcPixel, dstPixel; + int xorRGB = xorcolor.getRGB(); + int srcRGB, dstRGB; + + for(int sy = srcY, dy = dstY, srcYMax = srcY + height; sy < srcYMax; sy++, dy++){ + for(int sx = srcX, dx = dstX, srcXMax = srcX + width; sx < srcXMax; sx++, dx++){ + srcPixel = srcRast.getDataElements(sx, sy, null); + dstPixel = dstRast.getDataElements(dx, dy, null); + + srcRGB = srcCM.getRGB(srcPixel); + dstRGB = dstCM.getRGB(dstPixel); + dstRGB = srcRGB ^ xorRGB ^ dstRGB; + + dstRGB = 0xff000000 | dstRGB; + dstPixel = dstCM.getDataElements(dstRGB, dstPixel); + dstRast.setDataElements(dx,dy,dstPixel); + + } + } + + } + + private void transformedBlit(ColorModel srcCM, Raster srcR, int srcX, int srcY, + ColorModel dstCM, WritableRaster dstR, int dstX, int dstY, + int width, int height, AffineTransform at, Composite comp, + Color bgcolor,MultiRectArea clip) { + + Rectangle srcBounds = new Rectangle(width, height); + Rectangle dstBlitBounds = new Rectangle(dstX, dstY, srcR.getWidth(), srcR.getHeight()); + + Rectangle transSrcBounds = getBounds2D(at, srcBounds).getBounds(); + Rectangle transDstBlitBounds = getBounds2D(at, dstBlitBounds).getBounds(); + + int translateX = transDstBlitBounds.x - transSrcBounds.x; + int translateY = transDstBlitBounds.y - transSrcBounds.y; + + AffineTransform inv = null; + try { + inv = at.createInverse(); + } catch (NoninvertibleTransformException e) { + return; + } + + double[] m = new double[6]; + inv.getMatrix(m); + + int clipRects[]; + if(clip != null) { + clipRects = clip.rect; + } else { + clipRects = new int[]{5, 0, 0, dstR.getWidth(), dstR.getHeight()}; + } + + int compType = 0; + int srcConstAlpha = 0; + int rule = 0; + int bgRGB = bgcolor == null ? 0 : bgcolor.getRGB(); + int srcRGB = 0, dstRGB = 0; + Object srcVal = null, dstVal = null; + if(comp instanceof AlphaComposite){ + compType = AlphaCompositeMode; + AlphaComposite ac = (AlphaComposite) comp; + rule = ac.getRule(); + srcConstAlpha = (int)(ac.getAlpha() * 255 + 0.5f); + }else if(comp instanceof XORComposite){ + compType = XORMode; + XORComposite xor = (XORComposite) comp; + bgRGB = xor.getXORColor().getRGB(); + } + + for(int i = 1; i < clipRects[0]; i += 4){ + Rectangle dstBounds = new Rectangle(clipRects[i], clipRects[i + 1], 0, 0); + dstBounds.add(clipRects[i + 2] + 1, clipRects[i + 1]); + dstBounds.add(clipRects[i + 2] + 1, clipRects[i + 3] + 1); + dstBounds.add(clipRects[i], clipRects[i + 3] + 1); + + Rectangle bounds = dstBounds.intersection(transDstBlitBounds); + + int minSrcX = srcBounds.x; + int minSrcY = srcBounds.y; + int maxSrcX = minSrcX + srcBounds.width; + int maxSrcY = minSrcY + srcBounds.height; + + int minX = bounds.x; + int minY = bounds.y; + int maxX = minX + bounds.width; + int maxY = minY + bounds.height; + + int hx = (int)((m[0] * 256) + 0.5); + int hy = (int)((m[1] * 256) + 0.5); + int vx = (int)((m[2] * 256) + 0.5); + int vy = (int)((m[3] * 256) + 0.5); + int sx = (int)((m[4] + m[0] * (bounds.x - translateX) + m[2] * (bounds.y - translateY)) * 256 + 0.5); + int sy = (int)((m[5] + m[1] * (bounds.x - translateX) + m[3] * (bounds.y - translateY)) * 256 + 0.5); + + vx -= hx * bounds.width; + vy -= hy * bounds.width; + + for(int y = minY; y < maxY; y++) { + for(int x = minX; x < maxX; x++) { + int px = sx >> 8; + int py = sy >> 8; + if (px >= minSrcX && py >= minSrcY && px < maxSrcX && py < maxSrcY) { + switch(compType){ + case AlphaCompositeMode: + srcVal = srcR.getDataElements(px , py , null); + srcRGB = srcCM.getRGB(srcVal); + if(bgcolor != null){ + dstRGB = bgRGB; + }else{ + dstVal = dstR.getDataElements(x, y, null); + dstRGB = dstCM.getRGB(dstVal); + } + dstRGB = compose(srcRGB, srcCM.isAlphaPremultiplied(), + dstRGB, dstCM.hasAlpha(), dstCM.isAlphaPremultiplied(), + rule, srcConstAlpha); + dstVal = dstCM.getDataElements(dstRGB, null); + dstR.setDataElements(x, y, dstVal); + break; + + case XORMode: + srcVal = srcR.getDataElements(px , py , null); + srcRGB = srcCM.getRGB(srcVal); + dstVal = dstR.getDataElements(x, y, null); + dstRGB = dstCM.getRGB(dstVal); + dstRGB = srcRGB ^ bgRGB; + + dstRGB = 0xff000000 | dstRGB; + dstVal = dstCM.getDataElements(dstRGB, null); + dstR.setDataElements(x, y, dstVal); + break; + + default: + // awt.37=Unknown composite type {0} + throw new IllegalArgumentException(Messages.getString("awt.37", //$NON-NLS-1$ + comp.getClass())); + } + } + sx += hx; + sy += hy; + } + sx += vx; + sy += vy; + } + } + + } + + private Rectangle2D getBounds2D(AffineTransform at, Rectangle r) { + int x = r.x; + int y = r.y; + int width = r.width; + int height = r.height; + + float[] corners = { + x, y, + x + width, y, + x + width, y + height, + x, y + height + }; + + at.transform(corners, 0, corners, 0, 4); + + Rectangle2D.Float bounds = new Rectangle2D.Float(corners[0], corners[1], 0 , 0); + bounds.add(corners[2], corners[3]); + bounds.add(corners[4], corners[5]); + bounds.add(corners[6], corners[7]); + + return bounds; + } + + private int compose(int srcRGB, boolean isSrcAlphaPre, + int dstRGB, boolean dstHasAlpha, boolean isDstAlphaPre, + int rule, int srcConstAlpha){ + + int sa, sr, sg, sb, da, dr, dg, db; + + sa = (srcRGB >> 24) & 0xff; + sr = (srcRGB >> 16) & 0xff; + sg = (srcRGB >> 8) & 0xff; + sb = srcRGB & 0xff; + + if(isSrcAlphaPre){ + sa = mulLUT[srcConstAlpha][sa] & 0xff; + sr = mulLUT[srcConstAlpha][sr] & 0xff; + sg = mulLUT[srcConstAlpha][sg] & 0xff; + sb = mulLUT[srcConstAlpha][sb] & 0xff; + }else{ + sa = mulLUT[srcConstAlpha][sa] & 0xff; + sr = mulLUT[sa][sr] & 0xff; + sg = mulLUT[sa][sg] & 0xff; + sb = mulLUT[sa][sb] & 0xff; + } + + da = (dstRGB >> 24) & 0xff; + dr = (dstRGB >> 16) & 0xff; + dg = (dstRGB >> 8) & 0xff; + db = dstRGB & 0xff; + + if(!isDstAlphaPre){ + dr = mulLUT[da][dr] & 0xff; + dg = mulLUT[da][dg] & 0xff; + db = mulLUT[da][db] & 0xff; + } + + int Fs = 0; + int Fd = 0; + switch(rule){ + case AlphaComposite.CLEAR: + break; + + case AlphaComposite.DST: + Fd = 255; + break; + + case AlphaComposite.DST_ATOP: + Fs = 255 - da; + Fd = sa; + break; + + case AlphaComposite.DST_IN: + Fd = sa; + break; + + case AlphaComposite.DST_OUT: + Fd = 255 - sa; + break; + + case AlphaComposite.DST_OVER: + Fs = 255 - da; + Fd = 255; + break; + + case AlphaComposite.SRC: + Fs = 255; + break; + + case AlphaComposite.SRC_ATOP: + Fs = da; + Fd = 255 - sa; + break; + + case AlphaComposite.SRC_IN: + Fs = da; + break; + + case AlphaComposite.SRC_OUT: + Fs = 255 - da; + break; + + case AlphaComposite.SRC_OVER: + Fs = 255; + Fd = 255 - sa; + break; + + case AlphaComposite.XOR: + Fs = 255 - da; + Fd = 255 - sa; + break; + } + dr = (mulLUT[sr][Fs] & 0xff) + (mulLUT[dr][Fd] & 0xff); + dg = (mulLUT[sg][Fs] & 0xff) + (mulLUT[dg][Fd] & 0xff); + db = (mulLUT[sb][Fs] & 0xff) + (mulLUT[db][Fd] & 0xff); + + da = (mulLUT[sa][Fs] & 0xff) + (mulLUT[da][Fd] & 0xff); + + if(!isDstAlphaPre){ + if(da != 255){ + dr = divLUT[da][dr] & 0xff; + dg = divLUT[da][dg] & 0xff; + db = divLUT[da][db] & 0xff; + } + } + if(!dstHasAlpha) { + da = 0xff; + } + dstRGB = (da << 24) | (dr << 16) | (dg << 8) | db; + + return dstRGB; + + } + +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/render/JavaLineRasterizer.java b/app/src/main/java/org/apache/harmony/awt/gl/render/JavaLineRasterizer.java new file mode 100644 index 000000000..eb6f7b5cb --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/render/JavaLineRasterizer.java @@ -0,0 +1,760 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Denis M. Kishenko + * @version $Revision$ + */ +package org.apache.harmony.awt.gl.render; + +import org.apache.harmony.awt.gl.MultiRectArea; + + +public class JavaLineRasterizer { + + /** + * LineDasher class provides dashing for particular dash style + */ + public static class LineDasher { + + int index; + float pos; + float phase; + float dash[]; + float inv[]; + boolean visible; + + public LineDasher() { + } + + public LineDasher(float dash[], float phase) { + this.dash = dash; + this.phase = phase; + + inv = new float[dash.length]; + int j = dash.length; + for (float element : dash) { + inv[--j] = element; + } + index = 0; + while (phase > dash[index]) { + phase -= dash[index]; + index = (index + 1) % dash.length; + } + visible = index % 2 == 0; + } + + void move(float step) { // main dasher + pos += step; + step += phase; + while(step >= dash[index]) { + step -= dash[index]; + index = (index + 1) % dash.length; + visible = !visible; + } + phase = step; + } + + float nextDash() { + phase = 0.0f; + index = (index + 1) % dash.length; + visible = !visible; + return dash[index]; + } + + LineDasher createDiagonal(double k, float length, boolean invert) { + LineDasher local = new LineDasher(); + local.dash = new float[dash.length]; + if (invert) { // inverted dasher + move(length); + local.phase = (float)((dash[index] - phase) * k); + local.visible = visible; + local.index = inv.length - index - 1; + for(int i = 0; i < inv.length; i++) { + local.dash[i] = (float)(inv[i] * k); + } + } else { + local.phase = (float)(phase * k); + local.visible = visible; + local.index = index; + for(int i = 0; i < dash.length; i++) { + local.dash[i] = (float)(dash[i] * k); + } + move(length); + } + return local; + } + + LineDasher createOrtogonal(float length, boolean invert) { + LineDasher local = new LineDasher(); + local.dash = new float[dash.length]; + if (invert) { // inverted dasher + move(length); + local.phase = dash[index] - phase; + local.visible = visible; + local.index = inv.length - index - 1; + local.dash = inv; + } else { + local.phase = phase; + local.visible = visible; + local.index = index; + local.dash = dash; + move(length); + } + return local; + } + + LineDasher createChild(float start) { + LineDasher child = new LineDasher(); + child.phase = phase; + child.visible = visible; + child.index = index; + child.dash = dash; + child.move(start); + return child; + } + + } + + /** + * Line class provides rasterization for different line types + */ + abstract static class Line { + + int x1, y1, x2, y2; + int x, y; + MultiRectArea dst; + + Line(int x1, int y1, int x2, int y2, MultiRectArea dst) { + this.x1 = x1; + this.y1 = y1; + this.x2 = x2; + this.y2 = y2; + this.dst = dst; + } + + static abstract class Diag extends Line { + int dx, dy, adx, ady, sx, sy; + int eBase, ePos, eNeg; + int xcount; + int e; + + Diag(int x1, int y1, int x2, int y2, MultiRectArea dst) { + super(x1, y1, x2, y2, dst); + dx = x2 - x1; + dy = y2 - y1; + sy = 1; + if (dx > 0) { + adx = dx; + sx = 1; + } else { + adx = -dx; + sx = -1; + } + ady = dy; + } + + float getLength() { + return (float)Math.sqrt(dx * dx + dy * dy); + } + + static class Hor extends Diag { + + Hor(int x1, int y1, int x2, int y2, MultiRectArea dst) { + super(x1, y1, x2, y2, dst); + eBase = ady + ady - adx; + ePos = 2 * (ady - adx); + eNeg = ady + ady; + xcount = adx; + } + + @Override + void rasterize() { + e = eBase; + x = x1; + y = y1; + rasterize(xcount); + } + + @Override + void rasterizeClipped(int nx1, int ny1, int nx2, int ny2) { + e = eBase + 2 * (ady * Math.abs(nx1 - x1) - adx * Math.abs(ny1 - y1)); + x = nx1; + y = ny1; + rasterize(dx > 0 ? nx2 - nx1 : nx1 - nx2); + } + + @Override + void rasterize(int count) { + int px = x; + while (count-- > 0) { + if (e >= 0) { + if (sx > 0) { + dst.addRect(px, y, x, y); + } else { + dst.addRect(x, y, px, y); + } + x += sx; + y += sy; + e += ePos; + px = x; + } else { + e += eNeg; + x += sx; + } + } + if (sx > 0) { + dst.addRect(px, y, x, y); + } else { + dst.addRect(x, y, px, y); + } + } + + @Override + void skip(int count) { + while (count-- > 0) { + x += sx; + if (e >= 0) { + y += sy; + e += ePos; + } else { + e += eNeg; + } + } + } + + } + + static class Ver extends Diag { + + Ver(int x1, int y1, int x2, int y2, MultiRectArea dst) { + super(x1, y1, x2, y2, dst); + eBase = adx + adx - ady; + ePos = 2 * (adx - ady); + eNeg = adx + adx; + xcount = ady; + } + + @Override + void rasterize() { + e = eBase; + x = x1; + y = y1; + rasterize(xcount); + } + + @Override + void rasterizeClipped(int nx1, int ny1, int nx2, int ny2) { + e = eBase + 2 * (adx * Math.abs(ny1 - y1) - ady * Math.abs(nx1 - x1)); + x = nx1; + y = ny1; + rasterize(ny2 - ny1); + } + + @Override + void rasterize(int count) { + int py = y; + while (count-- > 0) { + if (e >= 0) { + dst.addRect(x, py, x, y); + x += sx; + y += sy; + e += ePos; + py = y; + } else { + y += sy; + e += eNeg; + } + } + dst.addRect(x, py, x, y); + } + + @Override + void skip(int count) { + while (count-- > 0) { + y += sy; + if (e >= 0) { + x += sx; + e += ePos; + } else { + e += eNeg; + } + } + } + + } + + static class HorDashed extends Hor { + + LineDasher local; + + HorDashed(int x1, int y1, int x2, int y2, MultiRectArea dst, LineDasher dasher, boolean invert) { + super(x1, y1, x2, y2, dst); + float length = getLength(); + local = dasher.createDiagonal(xcount / length, length, invert); + } + + @Override + void rasterize() { + e = eBase; + x = x1; + y = y1; + rasterizeDash(xcount, local); + } + + @Override + void rasterizeClipped(int nx1, int ny1, int nx2, int ny2) { + e = eBase + 2 * (ady * Math.abs(nx1 - x1) - adx * Math.abs(ny1 - y1)); + x = nx1; + y = ny1; + rasterizeDash(Math.abs(nx2 - nx1), local.createChild(Math.abs(nx1 - x1))); + } + + } + + static class VerDashed extends Ver { + + LineDasher local; + + VerDashed(int x1, int y1, int x2, int y2, MultiRectArea dst, LineDasher dasher, boolean invert) { + super(x1, y1, x2, y2, dst); + float length = getLength(); + local = dasher.createDiagonal(xcount / length, length, invert); + } + + @Override + void rasterize() { + e = eBase; + x = x1; + y = y1; + rasterizeDash(xcount, local); + } + + @Override + void rasterizeClipped(int nx1, int ny1, int nx2, int ny2) { + e = eBase + 2 * (adx * Math.abs(ny1 - y1) - ady * Math.abs(nx1 - x1)); + x = nx1; + y = ny1; + rasterizeDash(ny2 - ny1, local.createChild(ny1 - y1)); + } + + } + + @Override + void rasterize(int[] clip, int index) { + int cx1 = clip[index + 0]; + int cy1 = clip[index + 1]; + int cx2 = clip[index + 2] + 1; + int cy2 = clip[index + 3] + 1; + + int code1 = + (x1 < cx1 ? 1 : 0) | (x1 >= cx2 ? 2 : 0) | + (y1 < cy1 ? 8 : 0) | (y1 >= cy2 ? 4 : 0); + int code2 = + (x2 < cx1 ? 1 : 0) | (x2 >= cx2 ? 2 : 0) | + (y2 < cy1 ? 8 : 0) | (y2 >= cy2 ? 4 : 0); + + // Outside + if ((code1 & code2) != 0) { + return; + } + + // Inside + if (code1 == 0 && code2 == 0) { + rasterize(); + return; + } + + // Clip + int nx1 = x1; + int ny1 = y1; + int nx2 = x2; + int ny2 = y2; + // need to clip + cx1 -= x1; cx2 -= x1; + cy1 -= y1; cy2 -= y1; +// int d; + int newx1 = 0, newy1 = 0, newx2 = 0, newy2 = 0; + if (code1 != 0) { + newx1 = Integer.MAX_VALUE; + if ((code1 & 8) != 0) { + // clip point 1 with top clip bound + newy1 = cy1; + newx1 = clipY(dx, dy, newy1, true); + + } else if ((code1 & 4) != 0) { + // clip point 1 with bottom clip bound + newy1 = cy2 - 1; + newx1 = clipY(dx, dy, newy1, false); + } + if ((code1 & 1) != 0 && (cx1 > newx1 || newx1 == Integer.MAX_VALUE)) { + // clip point 1 with left clip bound + newx1 = cx1; + newy1 = clipX(dx, dy, newx1, false); + } else if ((code1 & 2) != 0 && (newx1 >= cx2 || newx1 == Integer.MAX_VALUE)) { + // clip point 1 with right clip bound + newx1 = cx2 - 1; + newy1 = clipX(dx, dy, newx1, false); + } + if (newx1 < cx1 || newx1 >= cx2 || newy1 < cy1 || newy1 >= cy2) { + return; + } +// d = 2 * (ady * Math.abs(newx1) - adx * Math.abs(newy1)) + 2 * ady - adx; + } else { +// d = (ady << 1) - adx; + } + + if (code2 != 0) { + newx2=Integer.MAX_VALUE; + if ((code2 & 8) != 0) { + // clip point 2 with top clip bound + newy2 = cy1; + newx2 = clipY(dx, dy, newy2, true); + } else if ((code2 & 4) != 0) { + // clip point 2 with bottom clip bound + newy2 = cy2 - 1; + newx2 = clipY(dx, dy, newy2, false); + } + if ((code2 & 1) != 0 && (cx1 > newx2 || newx2 == Integer.MAX_VALUE)) { + // clip point 2 with left clip bound + newx2 = cx1; + newy2 = clipX(dx, dy, newx2, false); + } else if ((code2 & 2) != 0 && (newx2 >= cx2 || newx2 == Integer.MAX_VALUE)) { + // clip point 2 with right clip bound + newx2 = cx2 - 1; + newy2 = clipX(dx, dy, newx2, false); + } + if (newx2 < cx1 || newx2 >= cx2 || newy2 < cy1 || newy2 >= cy2) { + return; + } + nx2 = x1 + newx2; + ny2 = y1 + newy2; + } + nx1 = x1 + newx1; + ny1 = y1 + newy1; + + rasterizeClipped(nx1, ny1, nx2, ny2); + } + + abstract void rasterizeClipped(int nx1, int ny1, int nx2, int ny2); + + } + + static abstract class Ortog extends Line { + + Ortog(int x1, int y1, int x2, int y2, MultiRectArea dst) { + super(x1, y1, x2, y2, dst); + } + + static class Hor extends Ortog { + + int dx; + + Hor(int x1, int y1, int x2, int y2, MultiRectArea dst) { + super(x1, y1, x2, y2, dst); + dx = x2 - x1; + } + + @Override + void rasterize() { + if (dx > 0) { + dst.addRect(x1, y1, x2, y2); + } else { + dst.addRect(x2, y2, x1, y1); + } + } + + @Override + void rasterize(int step) { + int px = x; + if (dx > 0) { + x += step; + dst.addRect(px, y1, x - 1, y2); + } else { + x -= step; + dst.addRect(x + 1, y2, px, y1); + } + } + + @Override + void skip(int step) { + if (dx > 0) { + x += step; + } else { + x -= step; + } + } + + void rasterizeClipped(int nx1, int nx2) { + if (nx1 < nx2) { + dst.addRect(nx1, y1, nx2, y1); + } else { + dst.addRect(nx2, y1, nx1, y1); + } + } + + @Override + void rasterize(int[] clip, int index) { + if (y1 >= clip[index + 1] && y1 <= clip[index + 3]) { + int cx1 = clip[index + 0]; + int cx2 = clip[index + 2]; + if (x1 <= cx2 && x2 >= cx1) { + int nx1, nx2; + if (dx > 0) { + nx1 = Math.max(x1, cx1); + nx2 = Math.min(x2, cx2); + } else { + nx2 = Math.max(x2, cx1); + nx1 = Math.min(x1, cx2); + } + rasterizeClipped(nx1, nx2); + } + } + } + + } + + static class Ver extends Ortog { + + int dy; + + Ver(int x1, int y1, int x2, int y2, MultiRectArea dst) { + super(x1, y1, x2, y2, dst); + dy = y2 - y1; + } + + @Override + void rasterize() { + dst.addRect(x1, y1, x2, y2); + } + + @Override + void rasterize(int step) { + int py = y; + y += step; + dst.addRect(x1, py, x2, y - 1); + } + + @Override + void skip(int step) { + y += step; + } + + void rasterizeClipped(int ny1, int ny2) { + dst.addRect(x1, ny1, x1, ny2); + } + + @Override + void rasterize(int[] clip, int index) { + if (x1 >= clip[index] && x1 <= clip[index + 2]) { + int cy1 = clip[index + 1]; + int cy2 = clip[index + 3]; + if (y1 <= cy2 && y2 >= cy1) { + rasterizeClipped(Math.max(y1, cy1), Math.min(y2, cy2)); + } + } + } + + } + + static class HorDashed extends Hor { + + LineDasher local; + + HorDashed(int x1, int y1, int x2, int y2, MultiRectArea dst, LineDasher dasher) { + super(x1, y1, x2, y2, dst); + dx = x2 - x1; + local = dasher.createOrtogonal(Math.abs(dx), false); + } + + @Override + void rasterize() { + x = x1; + y = y1; + rasterizeDash(Math.abs(dx), local); + } + + @Override + void rasterizeClipped(int nx1, int nx2) { + x = nx1; + y = y1; + rasterizeDash(Math.abs(nx2 - nx1), local.createChild(Math.abs(nx1 - x1))); + } + + } + + static class VerDashed extends Ver { + + LineDasher local; + + VerDashed(int x1, int y1, int x2, int y2, MultiRectArea dst, LineDasher dasher, boolean invert) { + super(x1, y1, x2, y2, dst); + dy = y2 - y1; + local = dasher.createOrtogonal(dy, invert); + } + + @Override + void rasterize() { + x = x1; + y = y1; + rasterizeDash(dy, local); + } + + @Override + void rasterizeClipped(int ny1, int ny2) { + x = x1; + y = ny1; + rasterizeDash(ny2 - ny1, local.createChild(ny1)); + } + + } + + } + + abstract void rasterize(); + abstract void rasterize(int[] clip, int index); + abstract void rasterize(int count); + abstract void skip(int count); + + void rasterizeDash(int count, LineDasher dasher) { + float delta = dasher.dash[dasher.index] - dasher.phase; + int step = (int)delta; + delta -= step; + while(count > step) { + if (dasher.visible) { + rasterize(step); + } else { + skip(step); + } + count -= step; + delta += dasher.nextDash(); + step = (int)delta; + delta -= step; + } + if (count > 0 && dasher.visible) { + rasterize(count); + dasher.move(count); + } + } + + } + + /** + * Common clipping method + */ + static int clip(int dX1, int dX2, int cX, boolean top) { + int adX1 = dX1 < 0 ? -dX1 : dX1; + int adX2 = dX2 < 0 ? -dX2 : dX2; + if (adX1 <= adX2) { + // obtuse intersection angle + return ((dX1 << 1) * cX + (dX1 > 0 ? dX2 : -dX2)) / (dX2 << 1); + } + int k; + if (top) { + k = -dX1 + (dX2 < 0 ? 0 : dX1 > 0 ? (dX2 << 1) : -(dX2 << 1)); + } else { + k = dX1 + (dX2 > 0 ? 0 : dX1 > 0 ? (dX2 << 1) : -(dX2 << 1)); + } + + k += dX1 > 0 == dX2 > 0 ? -1 : 1; + return ((dX1 << 1) * cX + k) / (dX2 << 1); + } + + /** + * Clipping along X axis + */ + static int clipX(int dx, int dy, int cy, boolean top) { + return clip(dy, dx, cy, top); + } + + /** + * Clipping along Y axis + */ + static int clipY(int dx, int dy, int cx, boolean top) { + return clip(dx, dy, cx, top); + } + + /** + * Rasterizes line using clippind and dashing style + * @param x1 - the x coordinate of the first control point + * @param y1 - the y coordinate of the first control point + * @param x2 - the x coordinate of the second control point + * @param y2 - the y coordinate of the second control point + * @param clip - the MultiRectArea object of clipping area + * @param dasher - the dasher style + * @param invert - the invert indicator, always false + * @return a MultiRectArea of rasterizer line + */ + public static MultiRectArea rasterize(int x1, int y1, int x2, int y2, MultiRectArea clip, LineDasher dasher, boolean invert) { + + MultiRectArea dst = new MultiRectArea(false); + int dx = x2 - x1; + int dy = y2 - y1; + + // Point + if (dx == 0 && dy == 0) { + if ((clip == null || clip.contains(x1, y1)) && (dasher == null || dasher.visible)) { + dst = new MultiRectArea(x1, y1, x1, y1); + } + return dst; + } + + if (dy < 0) { + return rasterize(x2, y2, x1, y1, clip, dasher, true); + } + + Line line; + if (dasher == null) { + if (dx == 0) { + line = new Line.Ortog.Ver(x1, y1, x2, y2, dst); + } else + if (dy == 0) { + line = new Line.Ortog.Hor(x1, y1, x2, y2, dst); + } else { + if (dy < Math.abs(dx)) { + line = new Line.Diag.Hor(x1, y1, x2, y2, dst); + } else { + line = new Line.Diag.Ver(x1, y1, x2, y2, dst); + } + } + } else { + if (dx == 0) { + line = new Line.Ortog.VerDashed(x1, y1, x2, y2, dst, dasher, invert); + } else + if (dy == 0) { + line = new Line.Ortog.HorDashed(x1, y1, x2, y2, dst, dasher); + } else { + if (dy < Math.abs(dx)) { + line = new Line.Diag.HorDashed(x1, y1, x2, y2, dst, dasher, invert); + } else { + line = new Line.Diag.VerDashed(x1, y1, x2, y2, dst, dasher, invert); + } + } + } + + + if (clip == null || clip.isEmpty()) { + line.rasterize(); + } else { + for(int i = 1; i < clip.rect[0]; i += 4) { + line.rasterize(clip.rect, i); + } + } + + return dst; + } + +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/render/JavaShapeRasterizer.java b/app/src/main/java/org/apache/harmony/awt/gl/render/JavaShapeRasterizer.java new file mode 100644 index 000000000..cb2cc18c1 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/render/JavaShapeRasterizer.java @@ -0,0 +1,475 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Denis M. Kishenko + * @version $Revision$ + */ +package org.apache.harmony.awt.gl.render; + +import java.awt.Shape; +import java.awt.geom.PathIterator; + +import org.apache.harmony.awt.gl.MultiRectArea; +import org.apache.harmony.awt.internal.nls.Messages; + +public class JavaShapeRasterizer { + + static final int POINT_CAPACITY = 16; + + int edgesCount; + int edgeCur; + int[] edgesX; + int[] edgesY; + int[] edgesYS; // Y coordinate of edge START point + int[] edgesN; + int[] edgesDY; + int[] bounds; + int boundCount; + boolean[] edgesExt; // Extremal points + + int activeCount; + float[] activeX; + int[] activeYEnd; + float[] activeXStep; + int[] activeDY; + boolean[] activeExt; + + int[] crossX; + int[] crossDY; + + Filler filler; + + /** + * Rasterization filler for different path rules + */ + static abstract class Filler { + + static class NonZero extends Filler { + @Override + void add(MultiRectArea.LineCash rect, int[] points, int[] orient, int length, int y) { + + int[] dst = new int[length]; + int dstLength = 1; + dst[0] = points[0]; + int count = 0; + boolean inside = true; + for(int i = 0; i < length; i++) { + count += orient[i] > 0 ? 1 : -1; + if (count == 0) { + dst[dstLength++] = points[i]; + inside = false; + } else { + if (!inside) { + dst[dstLength++] = points[i]; + inside = true; + } + } + + } + + for(int i = 1; i < dstLength; i += 2) { + dst[i]--; + } + + dstLength = excludeEmpty(dst, dstLength); +// System.out.println("test"); + + dstLength = union(dst, dstLength); + + rect.addLine(dst, dstLength); + } + } + + static class EvenOdd extends Filler { + @Override + void add(MultiRectArea.LineCash rect, int[] points, int[] orient, int length, int y) { + /* + int[] buf = new int[length]; + int j = 0; + for(int i = 0; i < length - 1; i++) { + if (points[i] != points[i + 1]) { + buf[j++] = points[i]; + } + } + */ + for(int i = 1; i < length; i += 2) { + points[i]--; + } + + length = excludeEmpty(points, length); +// System.out.println("test"); + + length = union(points, length); + rect.addLine(points, length); + /* + for(int i = 0; i < length;) { + rect.add(points[i++], y, points[i++], y); + } + */ + } + } + + abstract void add(MultiRectArea.LineCash rect, int[] points, int[] orient, int length, int y); + + static int excludeEmpty(int[] points, int length) { + int i = 0; + while(i < length) { + if (points[i] <= points[i + 1]) { + i += 2; + } else { + length -= 2; + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(points, i + 2, points, i, length - i); + } + } + return length; + } + + static int union(int[] points, int length) { + int i = 1; + while(i < length - 1) { + if (points[i] < points[i - 1]) { + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(points, i + 1, points, i - 1, length - i - 1); + length -= 2; + } else + if (points[i] >= points[i + 1] - 1) { + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(points, i + 2, points, i, length - i - 2); + length -= 2; + } else { + i += 2; + } + } + return length; + } + + } + + public JavaShapeRasterizer() { + } + + /** + * Checks buffer size and realloc if necessary + */ + int[] checkBufSize(int[] buf, int size) { + if (size == buf.length) { + int[] tmp; + tmp = new int[size + POINT_CAPACITY]; + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(buf, 0, tmp, 0, buf.length); + buf = tmp; + } + return buf; + } + + /** + * Adds to the buffers new edge + */ + void addEdge(int x, int y, int num) { + edgesX = checkBufSize(edgesX, edgesCount); + edgesY = checkBufSize(edgesY, edgesCount); + edgesN = checkBufSize(edgesN, edgesCount); + edgesX[edgesCount] = x; + edgesY[edgesCount] = y; + edgesN[edgesCount] = (num << 16) | edgesCount; + edgesCount++; + } + + /** + * Prepare all buffers and variable to rasterize shape + */ + void makeBuffer(PathIterator path, double flatness) { + edgesX = new int[POINT_CAPACITY]; + edgesY = new int[POINT_CAPACITY]; + edgesN = new int[POINT_CAPACITY]; + bounds = new int[POINT_CAPACITY]; + boundCount = 0; + edgesCount = 0; + + if (path.getWindingRule() == PathIterator.WIND_EVEN_ODD) { + filler = new Filler.EvenOdd(); + } else { + filler = new Filler.NonZero(); + } + float[] coords = new float[2]; + boolean closed = true; + while (!path.isDone()) { + switch(path.currentSegment(coords)) { + case PathIterator.SEG_MOVETO: + if (!closed) { + boundCount++; + bounds = checkBufSize(bounds, boundCount); + bounds[boundCount] = edgesCount; + } + addEdge((int)coords[0], (int)coords[1], boundCount); + closed = false; + break; + case PathIterator.SEG_LINETO: + addEdge((int)coords[0], (int)coords[1], boundCount); + break; + case PathIterator.SEG_CLOSE: + boundCount++; + bounds = checkBufSize(bounds, boundCount); + bounds[boundCount] = edgesCount; + closed = true; + break; + default: + // awt.36=Wrong segment + throw new RuntimeException(Messages.getString("awt.36")); //$NON-NLS-1$ + } + path.next(); + } + if (!closed) { + boundCount++; + bounds = checkBufSize(bounds, boundCount); + bounds[boundCount] = edgesCount; + } + } + + /** + * Sort buffers + */ + void sort(int[] master, int[] slave, int length) { + for(int i = 0; i < length - 1; i++) { + int num = i; + int min = master[num]; + for(int j = i + 1; j < length; j++) { + if (master[j] < min) { + num = j; + min = master[num]; + } + } + if (num != i) { + master[num] = master[i]; + master[i] = min; + min = slave[num]; + slave[num] = slave[i]; + slave[i] = min; + } + } + } + + int getNext(int cur) { + int n = edgesN[cur]; + int bound = n >> 16; + int num = (n & 0xFFFF) + 1; + if (num == bounds[bound + 1]) { + return bounds[bound]; + } + return num; + } + + int getPrev(int cur) { + int n = edgesN[cur]; + int bound = n >> 16; + int num = (n & 0xFFFF) - 1; + if (num < bounds[bound]) { + return bounds[bound + 1] - 1; + } + return num; + } + + int getNextShape(int cur) { + int bound = edgesN[cur] >> 16; + return bounds[bound + 1]; + } + + void init() { + + edgesYS = new int[edgesCount]; + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(edgesY, 0, edgesYS, 0, edgesCount); + // Create edgesDY + edgesDY = new int[edgesCount]; + for(int i = 0; i < edgesCount; i++) { + int dy = edgesY[getNext(i)] - edgesY[i]; + edgesDY[i] = dy; + } + + // Create edgesExt + edgesExt = new boolean[edgesCount]; + int prev = -1; + int i = 0; + int pos = 0; + while(i < edgesCount) { + + TOP: { + do { + if (edgesDY[i] > 0) { + break TOP; + } + i = getNext(i); + } while (i != pos); + i = pos = getNextShape(i); + continue; + } + + BOTTOM: { + do { + if (edgesDY[i] < 0) { + break BOTTOM; + } + if (edgesDY[i] > 0) { + prev = i; + } + i = getNext(i); + } while (i != pos); + i = pos = getNextShape(i); + continue; + } + + if (prev != -1) { + edgesExt[prev] = true; + } + edgesExt[i] = true; + } + + // Sort edgesY and edgesN + sort(edgesYS, edgesN, edgesCount); + + edgeCur = 0; + activeCount = 0; + activeX = new float[edgesCount]; + activeYEnd = new int[edgesCount]; + activeXStep = new float[edgesCount]; + activeDY = new int[edgesCount]; + activeExt = new boolean[edgesCount]; + + crossX = new int[edgesCount]; + crossDY = new int[edgesCount]; + } + + /** + * Marks edge as active + */ + void addActiveEdge(int levelY, int start, int end, boolean back) { + int dy = back ? -edgesDY[end] : edgesDY[start]; + if (dy <= 0) { + return; + } + int x1 = edgesX[start]; + int dx = edgesX[end] - x1; + activeX[activeCount] = x1; + activeYEnd[activeCount] = edgesY[end]; + activeXStep[activeCount] = dx / (float)dy; + activeDY[activeCount] = back ? -dy : dy; + activeExt[activeCount] = back ? edgesExt[end] : edgesExt[start]; + activeCount++; + } + + /** + * Find new active edges + */ + int findActiveEdges(int levelY) { + + int edgeActive = edgeCur; + while (edgeActive < edgesCount && edgesYS[edgeActive] == levelY) { + edgeActive++; + } + + int activeNext = edgeActive; + + while (edgeActive > edgeCur) { + edgeActive--; + int num = edgesN[edgeActive] & 0xFFFF; + addActiveEdge(levelY, num, getPrev(edgeActive), true); + addActiveEdge(levelY, num, getNext(edgeActive), false); + } + + edgeCur = activeNext; + + if (activeNext == edgesCount) { + return edgesY[edgesCount - 1]; + } + return edgesYS[activeNext]; + } + + /** + * Rasterizes shape with particular flatness + * @param shape - the souze Shape to be rasterized + * @param flatness - the rasterization flatness + * @return a MultiRectArea of rasterized shape + */ + public MultiRectArea rasterize(Shape shape, double flatness) { + + PathIterator path = shape.getPathIterator(null, flatness); + + // Shape is empty + if (path.isDone()) { + return new MultiRectArea(); + } + + makeBuffer(path, flatness); + + init(); + + int y = edgesYS[0]; + int nextY = y; + int crossCount; + + MultiRectArea.LineCash rect = new MultiRectArea.LineCash(edgesCount); + rect.setLine(y); + + while(y <= nextY) { + + crossCount = 0; + + if (y == nextY) { + + int i = activeCount; + while(i > 0) { + i--; + if (activeYEnd[i] == y) { + + activeCount--; + int length = activeCount - i; + if (length != 0) { + int pos = i + 1; + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(activeX, pos, activeX, i, length); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(activeYEnd, pos, activeYEnd, i, length); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(activeXStep, pos, activeXStep, i, length); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(activeDY, pos, activeDY, i, length); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(activeExt, pos, activeExt, i, length); + } + } + } + + nextY = findActiveEdges(y); + } + + // Get X crossings + for(int i = 0; i < activeCount; i++) { + crossX[crossCount] = (int)Math.ceil(activeX[i]); + crossDY[crossCount] = activeDY[i]; + crossCount++; + } + + if (crossCount == 0) { + rect.skipLine(); + } else { + // Sort X crossings + sort(crossX, crossDY, crossCount); + filler.add(rect, crossX, crossDY, crossCount, y); + } + + for(int i = 0; i < activeCount; i++) { + activeX[i] += activeXStep[i]; + } + + y++; + } + + return rect; + } + +} diff --git a/app/src/main/java/org/apache/harmony/awt/gl/render/JavaTextRenderer.java b/app/src/main/java/org/apache/harmony/awt/gl/render/JavaTextRenderer.java new file mode 100644 index 000000000..322ba5769 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/gl/render/JavaTextRenderer.java @@ -0,0 +1,263 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ +package org.apache.harmony.awt.gl.render; + +import java.awt.*; +import java.awt.image.*; + + +import java.awt.font.GlyphMetrics; +import java.awt.font.GlyphVector; +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; + +import org.apache.harmony.awt.gl.TextRenderer; +import org.apache.harmony.awt.gl.font.CommonGlyphVector; +import org.apache.harmony.awt.gl.font.FontPeerImpl; +import org.apache.harmony.awt.gl.font.Glyph; +import org.apache.harmony.awt.gl.image.BufferedImageGraphics2D; + +public class JavaTextRenderer extends TextRenderer { + + public static final JavaTextRenderer inst = new JavaTextRenderer(); + + @Override + public void drawGlyphVector(Graphics2D g, GlyphVector glyphVector, + float x, float y) { + + AffineTransform at = g.getTransform(); + Rectangle c = g.getClipBounds(); + if (at != null){ + int atType = at.getType(); + if (atType == AffineTransform.TYPE_TRANSLATION) { + c.translate((int)Math.round(at.getTranslateX()), (int)Math.round(at.getTranslateY())); + } + } + + WritableRaster wr = ((BufferedImageGraphics2D)g).getWritableRaster(); + ColorModel cm = ((BufferedImageGraphics2D)g).getColorModel(); + + Rectangle rBounds = wr.getBounds(); + + Object color = cm.getDataElements(g.getColor().getRGB(), null); + + drawClipGlyphVector(wr, color, glyphVector, (int)Math.round(x + at.getTranslateX()), (int)Math.round(y + at.getTranslateY()), + Math.max(c.x,rBounds.x), + Math.max(c.y,rBounds.y), + Math.min((int)Math.round(c.getMaxX()), (int)Math.round(rBounds.getMaxX())), + Math.min((int)Math.round(c.getMaxY()), (int)Math.round(rBounds.getMaxY()))); + + } + + @SuppressWarnings("deprecation") + @Override + public void drawString(Graphics2D g, String str, float x, float y) { + AffineTransform at = g.getTransform(); + Rectangle c = g.getClipBounds(); + if (at != null){ + int atType = at.getType(); + if (atType == AffineTransform.TYPE_TRANSLATION) { + c.translate((int)Math.round(at.getTranslateX()), (int)Math.round(at.getTranslateY())); + } + } + WritableRaster wr = ((BufferedImageGraphics2D)g).getWritableRaster(); + ColorModel cm = ((BufferedImageGraphics2D)g).getColorModel(); + Rectangle rBounds = wr.getBounds(); + + Object color = cm.getDataElements(g.getColor().getRGB(), null); + + drawClipString(wr, color, str, (FontPeerImpl) (g.getFont().getPeer()), + (int)Math.round(x + at.getTranslateX()), (int)Math.round(y + at.getTranslateY()), + Math.max(c.x,rBounds.x), + Math.max(c.y,rBounds.y), + Math.min((int)Math.round(c.getMaxX()), (int)Math.round(rBounds.getMaxX())), + Math.min((int)Math.round(c.getMaxY()), (int)Math.round(rBounds.getMaxY()))); + + } + + /** + * + * Draws string on specified raster at desired position. + * + * @param raster specified WritableRaster to draw at + * @param color color of the text + * @param glyphVector GlyphVector object to draw + * @param x start X position to draw + * @param y start Y position to draw + * @param cMinX minimum x of the raster area to draw + * @param cMinY minimum y of the raster area to draw + * @param cMaxX maximum x of the raster area to draw + * @param cMaxY maximum y of the raster area to draw + */ + public void drawClipGlyphVector(WritableRaster raster, Object color, + GlyphVector glyphVector, int x, int y, + int cMinX, int cMinY, int cMaxX, int cMaxY) { + // TODO: implement complex clipping + + int xSrcSurf, ySrcSurf; // Start point in String rectangle + int xDstSurf, yDstSurf; // Start point in Surface rectangle + int clWidth, clHeight; + + for (int i = 0; i < glyphVector.getNumGlyphs(); i++) { + Glyph gl = ((CommonGlyphVector) glyphVector).vector[i]; + + if (gl.getPointWidth() == 0) { + continue; + } + + byte[] data = gl.getBitmap(); + if (data != null) { + Point2D pos = glyphVector.getGlyphPosition(i); + + xSrcSurf = 0;//gl.bmp_left; + ySrcSurf = 0;//gl.bmp_rows - gl.bmp_top; + + xDstSurf = x + (int)pos.getX() + (int) gl.getGlyphPointMetrics().getLSB();// + gl.bmp_left; + yDstSurf = y - gl.bmp_top/*getPointHeight()*/ + (int) pos.getY();// - (gl.bmp_rows-gl.bmp_top); + + int textWidth = gl.bmp_width; + int textHeight = gl.getPointHeight(); + + // if Regions don't intersect + if ((xDstSurf > cMaxX) || (yDstSurf > cMaxY) || (xDstSurf + textWidth < cMinX) + || (yDstSurf + textHeight < cMinY)) { + // Nothing to do + } else { + if (xDstSurf >= cMinX) { + clWidth = Math.min(textWidth, cMaxX - xDstSurf); + } else { + xSrcSurf += cMinX - xDstSurf; + clWidth = Math.min(cMaxX - cMinX, textWidth - (cMinX - xDstSurf)); + xDstSurf = cMinX; + } + if (yDstSurf >= cMinY) { + clHeight = Math.min(textHeight, cMaxY - yDstSurf); + } else { + ySrcSurf += cMinY - yDstSurf; + clHeight = Math.min(cMaxY - cMinY, textHeight - (cMinY - yDstSurf)); + yDstSurf = cMinY; + } + // Drawing on the Raster + for (int h=0; h cMaxX) || (yDstSurf > cMaxY) || (xDstSurf + textWidth < cMinX) + || (yDstSurf + textHeight < cMinY)) { + // Nothing to do + } else { + if (xDstSurf >= cMinX) { + clWidth = Math.min(textWidth, cMaxX - xDstSurf); + } else { + xSrcSurf += cMinX - xDstSurf; + clWidth = Math.min(cMaxX - cMinX, textWidth - (cMinX - xDstSurf)); + xDstSurf = cMinX; + } + if (yDstSurf >= cMinY) { + clHeight = Math.min(textHeight, cMaxY - yDstSurf); + } else { + ySrcSurf += cMinY - yDstSurf; + clHeight = Math.min(cMaxY - cMinY, textHeight - (cMinY - yDstSurf)); + yDstSurf = cMinY; + } + + // Drawing on the Raster + for (int h=0; h imInstances; // Map + private final Map localeIM; // Map last user-selected IM for locale + private final Set notifyIM; // set of IMs to notify of client window bounds changes + + /** + * a flag indicating that IM should be notified of client window + * position/visibility changes as soon as it is activated(new client + * appears) + */ + private boolean pendingClientNotify; + private Component nextComp; // component to gain focus after endComposition() + //???AWT: private final Set imWindows; // set of all IM windows created by this instance + private final NativeIM nativeIM; + + + + public InputMethodContext() { + notifyIM = new HashSet(); +//???AWT: imWindows = new HashSet(); + imInstances = new HashMap(); + localeIM = new HashMap(); + selectInputMethod(Locale.US); // not default? + nativeIM = (NativeIM) inputMethod; + } + + //???AWT + /* + @Override + public void dispatchEvent(AWTEvent event) { + int id = event.getID(); + if ((id >= FocusEvent.FOCUS_FIRST) && (id <=FocusEvent.FOCUS_LAST)) { + dispatchFocusEvent((FocusEvent) event); + } else { + // handle special KEY_PRESSED + // event to show IM selection menu + if (id == KeyEvent.KEY_PRESSED) { + KeyEvent ke = (KeyEvent) event; + IMManager.selectIM(ke, this, + IMManager.getWindow(ke.getComponent())); + } + // dispatch all input events to the current IM: + if (inputMethod != null) { + inputMethod.dispatchEvent(event); + } + } + } + + private void dispatchFocusEvent(FocusEvent fe) { + switch (fe.getID()) { + case FocusEvent.FOCUS_LOST: + if (inputMethod != null) { + inputMethod.deactivate(fe.isTemporary()); + } + break; + case FocusEvent.FOCUS_GAINED: + + Component comp = fe.getComponent(); + if (imWindows.contains(comp)) { + // prevent activating when IM windows + // attached to this context gain focus + return; + } + InputMethodContext lastActive = IMManager.getLastActiveIMC(); + if ((lastActive != this) && (lastActive != null)) { + lastActive.hideWindows(); + } + if (inputMethod != null) { + activateIM(inputMethod); + if (!getCompositionWindow().isEmpty()) { + IMManager.showCompositionWindow(composeWindow); + } + if (client == comp) { + if (nextComp != null) { + // temporarily got focus to + // end composition + endComposition(); + + // transfer focus to new client + client = nextComp; + nextComp = null; + client.requestFocusInWindow(); + } + } else if ((client != null) && getCompositionWindow().isVisible()) { + // temporarily return focus back + // to previous client to be able + // to end composition + nextComp = comp; + client.requestFocusInWindow(); + } else { + client = comp; + } + } + if (pendingClientNotify) { + notifyClientWindowChange(IMManager.getWindow(comp).getBounds()); + } + break; + } + + } + + private void activateIM(InputMethod im) { + im.activate(); + if ((nativeIM != null) && (im != nativeIM)) { + // when Java IM is active + // native input method editor must be + // explicitly disabled + nativeIM.disableIME(); + } + IMManager.setLastActiveIMC(this); + } + + @SuppressWarnings("deprecation") + private void hideWindows() { + if (inputMethod != null) { + inputMethod.hideWindows(); + } + if (composeWindow != null) { + composeWindow.hide(); + } + } + + private void createCompositionWindow() { + composeWindow = new CompositionWindow(client); + } + + private CompositionWindow getCompositionWindow() { + if (composeWindow == null) { + createCompositionWindow(); + } + composeWindow.setClient(client); + return composeWindow; + } + */ + + /** + * Gets input method requests for the current client + * irrespective of input style. + * @return input method requests of composition window if + * client is passive, + * otherwise input method requests of client + */ + private InputMethodRequests getIMRequests() { + InputMethodRequests imRequests = null; + + if (client != null) { + imRequests = client.getInputMethodRequests(); + //???AWT + /* + if (imRequests == null) { + imRequests = getCompositionWindow().getInputMethodRequests(); + } + */ + } + + return imRequests; + } + + /** + * Gets input method requests for the current client & input style. + * @return input method requests of composition window if + * input style is "below-the-spot"(or client is passive), + * otherwise client input method requests + */ + private InputMethodRequests getStyleIMRequests() { + //???AWT + /* + if (IMManager.belowTheSpot()) { + return getCompositionWindow().getInputMethodRequests(); + } + */ + return getIMRequests(); + } + + @Override + public void dispose() { + if (inputMethod != null) { + closeIM(inputMethod); + inputMethod.dispose(); + } + notifyIM.clear(); + super.dispose(); + } + + @Override + public void endComposition() { + if (inputMethod != null) { + inputMethod.endComposition(); + } + super.endComposition(); + } + + @Override + public Object getInputMethodControlObject() { + if (inputMethod != null) { + return inputMethod.getControlObject(); + } + return super.getInputMethodControlObject(); + } + + @Override + public Locale getLocale() { + if (inputMethod != null) { + return inputMethod.getLocale(); + } + return super.getLocale(); + } + + @Override + public boolean isCompositionEnabled() { + if (inputMethod != null) { + return inputMethod.isCompositionEnabled(); + } + return super.isCompositionEnabled(); + } + + @Override + public void reconvert() { + if (inputMethod != null) { + inputMethod.reconvert(); + } + super.reconvert(); + } + + //???AWT + /* + @Override + public void removeNotify(Component client) { + if ((inputMethod != null) && (client == this.client)) { + inputMethod.removeNotify(); + client = null; + // set flag indicating that IM should be notified + // as soon as it is activated(new client appears) + pendingClientNotify = true; + } + + super.removeNotify(client); + } + */ + + @Override + public boolean selectInputMethod(Locale locale) { + + if ((inputMethod != null) && inputMethod.setLocale(locale)) { + return true; + } + // first + // take last user-selected IM for locale + InputMethod newIM = localeIM.get(locale); + + // if not found search through IM descriptors + // and take already created instance if exists + // or create, store new IM instance in descriptor->instance map + //???AWT + /* + if (newIM == null) { + try { + newIM = getIMInstance(IMManager.getIMDescriptors().iterator(), + locale); + } catch (Exception e) { + // ignore exceptions - just return false + } + } + */ + + return switchToIM(locale, newIM); + } + + private boolean switchToIM(Locale locale, InputMethod newIM) { + //???AWT + /* + if (newIM != null) { + closeIM(inputMethod); + client = KeyboardFocusManager. + getCurrentKeyboardFocusManager().getFocusOwner(); + initIM(newIM, locale); + inputMethod = newIM; + + return true; + } + */ + return false; + } + + /** + * Is called when IM is selected from UI + */ + void selectIM(InputMethodDescriptor imd, Locale locale) { + try { + switchToIM(locale, getIMInstance(imd)); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * Gets input method instance for the given + * locale from the given list of descriptors + * @param descriptors iterator of the list of IM descriptors + * @param locale the locale to be supported by the IM + * @return input method instance + * @throws Exception + */ + private InputMethod getIMInstance(Iterator descriptors, + Locale locale) throws Exception { + while (descriptors.hasNext()) { + InputMethodDescriptor desc = descriptors.next(); + Locale[] locs = desc.getAvailableLocales(); + for (Locale element : locs) { + if (locale.equals(element)) { + return getIMInstance(desc); + } + } + } + return null; + } + + private InputMethod getIMInstance(InputMethodDescriptor imd) throws Exception { + InputMethod im = imInstances.get(imd); + if (im == null) { + im = imd.createInputMethod(); + im.setInputMethodContext(this); + imInstances.put(imd, im); + } + return im; + } + + private void initIM(InputMethod im, Locale locale) { + if (im == null) { + return; + } + im.setLocale(locale); + im.setCharacterSubsets(null); + //???AWT: activateIM(im); + try { + im.setCompositionEnabled(inputMethod != null ? + inputMethod.isCompositionEnabled() : true); + } catch (UnsupportedOperationException uoe) { + + } + + } + + private void closeIM(InputMethod im) { + if (im == null) { + return; + } + if (im.isCompositionEnabled()) { + im.endComposition(); + } + + im.deactivate(true); + im.hideWindows(); + + } + + @Override + public void setCharacterSubsets(Subset[] subsets) { + if (inputMethod != null) { + inputMethod.setCharacterSubsets(subsets); + } + super.setCharacterSubsets(subsets); + } + + @Override + public void setCompositionEnabled(boolean enable) { + if (inputMethod != null) { + inputMethod.setCompositionEnabled(enable); + } + super.setCompositionEnabled(enable); + } + + //???AWT + /* + public JFrame createInputMethodJFrame(String title, + boolean attachToInputContext) { + JFrame jf = new IMJFrame(title, attachToInputContext ? this : null); + imWindows.add(jf); + return jf; + } + + public Window createInputMethodWindow(String title, + boolean attachToInputContext) { + Window w = new IMWindow(title, attachToInputContext ? this : null); + imWindows.add(w); + return w; + } + */ + + @SuppressWarnings("deprecation") + public void dispatchInputMethodEvent(int id, + AttributedCharacterIterator text, + int committedCharacterCount, + TextHitInfo caret, + TextHitInfo visiblePosition) { + if (client == null) { + return; + } + //???AWT + /* + InputMethodEvent ime = new InputMethodEvent(client, id, text, + committedCharacterCount, + caret, visiblePosition); + + + if ((client.getInputMethodRequests() != null) && + !IMManager.belowTheSpot()) { + + client.dispatchEvent(ime); + } else { + + // show/hide composition window if necessary + if (committedCharacterCount < text.getEndIndex()) { + IMManager.showCompositionWindow(getCompositionWindow()); + } else { + getCompositionWindow().hide(); + } + composeWindow.getActiveClient().dispatchEvent(ime); + } + */ + + } + + public void enableClientWindowNotification(InputMethod inputMethod, + boolean enable) { + if (enable) { + notifyIM.add(inputMethod); + //???AWT + /* + if (client != null) { + notifyClientWindowChange(IMManager.getWindow(client).getBounds()); + } else { + pendingClientNotify = true; + } + */ + } else { + notifyIM.remove(inputMethod); + } + + } + + public AttributedCharacterIterator cancelLatestCommittedText( + Attribute[] attributes) { + return getIMRequests().cancelLatestCommittedText(attributes); + } + + public AttributedCharacterIterator getCommittedText(int beginIndex, + int endIndex, + Attribute[] attributes) { + return getIMRequests().getCommittedText(beginIndex, endIndex, + attributes); + } + + public int getCommittedTextLength() { + return getIMRequests().getCommittedTextLength(); + } + + public int getInsertPositionOffset() { + return getIMRequests().getInsertPositionOffset(); + } + + public TextHitInfo getLocationOffset(int x, int y) { + InputMethodRequests imr = getStyleIMRequests(); + if (imr != null) { + return imr.getLocationOffset(x, y); + } + return null; + } + + public AttributedCharacterIterator getSelectedText(Attribute[] attributes) { + return getIMRequests().getSelectedText(attributes); + } + + public Rectangle getTextLocation(TextHitInfo offset) { + return getStyleIMRequests().getTextLocation(offset); + } + + /** + * To be called by AWT when client Window's bounds/visibility/state + * change + */ + public void notifyClientWindowChange(Rectangle bounds) { + if (notifyIM.contains(inputMethod)) { + inputMethod.notifyClientWindowChange(bounds); + } + pendingClientNotify = false; + } + + public final InputMethod getInputMethod() { + return inputMethod; + } + + public final Component getClient() { + return client; + } + + public final NativeIM getNativeIM() { + return nativeIM; + } +} diff --git a/app/src/main/java/org/apache/harmony/awt/internal/nls/messages.properties b/app/src/main/java/org/apache/harmony/awt/internal/nls/messages.properties new file mode 100644 index 000000000..9f647e9be --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/internal/nls/messages.properties @@ -0,0 +1,495 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# messages for EN locale +awt.00=FontRenderContext is null +awt.01='{0}' parameter is null +awt.02='{0}' parameter has zero length +awt.03='{0}' iterator parameter is null +awt.04='{0}' iterator parameter has zero length +awt.05=Operation cannot be null +awt.06=Unexpected type of the internal data buffer +awt.07=Transfer data is not available +awt.08=xfld parse string error: {0} +awt.09=min range bound value is greater than max range bound +awt.0A=Cannot use SinglePixedPackedSampleModel for bpp = {0} +awt.0B=Wrong color model created for drawable +awt.0C=Unknown visual class +awt.0D=Invalid transparency +awt.0E=Dimensions of the image should be positive +awt.0F=Cannot open display '{0}' +awt.10=Only 32-bit format is supported for window state operations. +awt.11=Invalid key code +awt.12=XTest is not supported by your X server\! +awt.13=Cannot allocate color named '{0}' +awt.14=Transfer data is not available +awt.15=Can not get monitor info +awt.16=Can not create DC for device +awt.17=Unknown Composite type : {0} +awt.18=Transparency is not supported +awt.19=Illegal size of volatile image +awt.1A=Failed to register window class {0} GetLastError returned {1} +awt.1B=Invalid key code +awt.1C=Failure to create JavaWindow GetLastError returned {0} +awt.1D=Cannot get data from OLE clipboard +awt.1E=Attempt to replace WindowProc handler +awt.1F=Waiting for resource access thread interrupted not from unlock method +awt.20=Can't unlock not locked resource +awt.21=Not owner can't unlock resource +awt.22=Not owner can't free resource +awt.23=One thread can't store state several times in a row +awt.24=Owner can't overwrite resource state. Lock operations may be lost +awt.25=No state stored for current thread +awt.26=Shutdown thread was interrupted while starting +awt.27=Shutdown thread was interrupted while stopping +awt.28=bad index: {0} +awt.29=Invalid range +awt.2A=Position not represented by view +awt.2B=No word at {0} +awt.2C=Invalid position: {0} +awt.2D=Invalid direction +awt.2E={0} not in range {1},{2} +awt.2F=No more words +awt.30=wrong number of elements to copy: {0}, size: {1} +awt.31=no room to copy: {0}, size: {1} +awt.32=String: '{0}' does not fit +awt.33=index is out of range +awt.34=Initial offset in the destination array is wrong: {0} +awt.35=Wrong number of elements to copy: {0} +awt.36=Wrong segment +awt.37=Unknown composite type {0} +awt.38=Property name is not defined +awt.39=This method is not implemented for image obtained from ImageProducer +awt.3A=Color Model is null +awt.3B=Incorrect ImageConsumer completion status +awt.3C=Unknown PNG color type +awt.3D=Unknown colorspace +awt.3E=Clone not supported +awt.3F=Invalid baseline index +awt.40=Wrong number of metrics\! +awt.41=Font returned unsupported type of line metrics. This case is known, but not supported yet. +awt.42=TextHitInfo out of range +awt.43=glyphIndex is out of vector's limits +awt.44=beginGlyphIndex is out of vector's range +awt.45=numEntries is out of vector's range +awt.46=length of setPositions array differs from the length of positions array +awt.47=First argument should be byte or short array +awt.48=The srcIn raster is incompatible with src ColorModel +awt.49=The dstIn raster is incompatible with dst ColorModel +awt.4A=The dstOut raster is incompatible with dst ColorModel +awt.4B=Iterator out of bounds +awt.4C=Invalid MultiRectArea in method {0} +awt.4D=The raster is incompatible with this ColorModel +awt.4E=Unknown native platform. +awt.4F=Data is not available +awt.50=Iterator is read-only +awt.51=Component expected to be a parent +awt.52=Time interval can't be <= 0 +awt.53=Handler can't be null +awt.54=Key event for unfocused component +awt.55=Double mouse enter event for component +awt.56=Double mouse exit event for component +awt.57=Double focus gained event for component +awt.58=Double focus lost event for component +awt.59=Application has run out of context thread group +awt.5A=Default class for PrinterJob is not found +awt.5B=No access to default class for PrinterJob +awt.5C=Instantiation exception for PrinterJob +awt.5D={0} is not supported +awt.5E=pageIndex is more than book size +awt.5F=wrong orientation +awt.60=Width and Height mustn't be equal zero both +awt.61=Unsupported data type: {0} +awt.62=Wrong mask : {0} +awt.63=Coordinates are not in bounds +awt.64=The number of the bands in the subset is greater than the number of bands in the sample model +awt.65=null argument +awt.66=Invalid format +awt.67=subclass is not derived from AWTKeyStroke +awt.68=subclass could not be instantiated +awt.69=columns less than zero. +awt.6A=rows less than zero. +awt.6B=Queue stack is empty +awt.6C=Event queue stack is broken +awt.6D=Point is null +awt.6E=Color is null +awt.6F=Index less than zero +awt.70=MenuItem is null +awt.71=Parent is null +awt.72=Key event for unfocused component +awt.73=no such item +awt.74=Input parameters a and b should not be null +awt.75=rows and cols cannot both be zero +awt.76=rows and cols cannot be negative +awt.77=default focus traversal policy cannot be null +awt.78=invalid focus traversal key identifier +awt.79=cannot set null focus traversal key +awt.7A=focus traversal keys cannot map to KEY_TYPED events +awt.7B=focus traversal keys must be unique for a Component +awt.7C=this KeyboardFocusManager is not installed in the current thread's context +awt.7D=Property name is null +awt.7E=invalid hotSpot +awt.7F=AddLayoutComponent: attempt to add null component +awt.80=AddLayoutComponent: constraint object must be GridBagConstraints +awt.81=AddLayoutComponent: {0} +awt.82=RemoveLayoutComponent: attempt to remove null component +awt.83=SetConstraints: attempt to get constraints of null component +awt.84=SetConstraints: attempt to set null constraints +awt.85=SetConstraints: {0} +awt.86=MinimumLayoutSize: {0} +awt.87=PreferredLayoutSize: {0} +awt.88=LayoutContainer: {0} +awt.89=LookupConstraints: attempt to get constraints of null component +awt.8A=AdjustForGravity: attempt to use null constraints +awt.8B=AdjustForGravity: attempt to use null rectangle +awt.8C=AdjustForGravity: {0} +awt.8D=REMINDER component expected after RELATIVE one +awt.8E=component is out of grid's range +awt.8F=Weights' overrides array is too long +awt.90=Lengths' overrides array is too long +awt.91=Unsupported constraints object: {0} +awt.92=Constraints object must be String +awt.93=cannot get component: invalid constraint: {0} +awt.94=transform can not be null +awt.95=Wrong start index: {0} +awt.96=Wrong finish index: {0} +awt.97=Wrong range length: {0} +awt.98=Wrong count value, can not be negative: {0} +awt.99=Wrong [start + count] is out of range: {0} +awt.9A=Unsupported font format +awt.9B=Can't create font - bad font data +awt.9C=wrong value of GridBagConstraints: {0} +awt.9D=relative grid size parameter goes after absolute grid coordinate +awt.9E=wrong values sum of GridBagConstraints' gridwidth and gridx +awt.9F=wrong values sum of GridBagConstraints' gridheight and gridy +awt.100=component has RELATIVE width and height +awt.101=position less than zero. +awt.102=columns less than zero. +awt.103=item is null +awt.104=item doesn't exist in the choice menu +awt.105=index less than zero +awt.106=specified position is greater than the number of items +awt.107=Color parameter outside of expected range: component {0} +awt.108=Alpha value outside of expected range +awt.109=Color parameter outside of expected range +awt.10A=Priority must be a value between 0 and 1, inclusive +awt.10B=aContainer and aComponent cannot be null +awt.10C=aContainer is not a focus cycle root of aComponent +awt.10D=aContainer should be focus cycle root or focus traversal policy provider +awt.10E=focusCycleRoot cannot be null +awt.10F=improper alignment: {0} +awt.110=Iterator out of bounds +awt.111=Parameter npoints is greater than array length +awt.112=Negative number of points +awt.113=illegal scrollbar orientation +awt.114=Image is null +awt.115=Anchor is null +awt.116=Invalid value for media +awt.117=Invalid value for orientationRequested +awt.118=Invalid value for printerResolution +awt.119=Invalid value for origin +awt.11A=Invalid value for printQuality +awt.11B=Invalid value for printerResolution[] +awt.11C=Invalid value for color +awt.11D=Unknown rule +awt.11E=Wrong alpha value +awt.11F=parent is not a component +awt.120=origin is not a descendant of parent +awt.121=parent must be showing on the screen +awt.122=Does not support display mode changes +awt.123=Unsupported display mode: {0} +awt.124=Cannot change the modality while the dialog is visible +awt.125=null owner window +awt.126=Window is showing +awt.127=Cannot change the decorations while the window is visible +awt.128=Graphics environment is headless +awt.129=Not a screen device +awt.12A=illegal component position +awt.12B=adding container to itself +awt.12C=adding container's parent to itself +awt.12D=adding a window to a container +awt.12E=Unknown component event id +awt.12F=Attempt to start nested mouse grab +awt.130=Attempt to grab mouse in not displayable window +awt.131=AddLayoutComponent: constraint object must be String +awt.132=wrong parent for CardLayout +awt.133=Negative width +awt.134=Illegal cap +awt.135=Illegal join +awt.136=miterLimit less than 1.0f +awt.137=Negative dashPhase +awt.138=Zero dash length +awt.139=Negative dash[{0}] +awt.13A=All dash lengths zero +awt.13B=offset off is out of range +awt.13C=number of elemets len is out of range +awt.13D=Rectangle width and height must be > 0 +awt.13E=Cannot call method from the event dispatcher thread +awt.13F=Delay must be to 0 to 60,000ms +awt.140=Invalid combination of button flags +awt.141=failed to parse hotspot property for cursor: +awt.142=Exception: class {0} {1} occurred while loading: {2} +awt.143=illegal cursor type +awt.144=Can be set by scrollpane only +awt.145=illegal file dialog mode +awt.146=illegal scrollbar display policy +awt.147=position greater than 0 +awt.148=child is null +awt.149=ScrollPane controls layout +awt.14A=Can not create VolatileImage with specified capabilities +awt.14B=Only Canvas or Window is allowed +awt.14C=Number of buffers must be greater than one +awt.14D=Buffer capabilities should support flipping +awt.14E=Component should be displayable +awt.14F=invalid focus traversal key identifier +awt.150=no parent +awt.151=component must be showing on the screen to determine its location +awt.152=Invalid number of copies +awt.153=Invalid value for maxPage +awt.154=Invalid value for minPage +awt.155=Invalid value for fromPage +awt.156=Invalid value for toPage +awt.157=Invalid value for pageRanges +awt.158=Invalid value for destination +awt.159=Invalid value for dialog +awt.15A=Invalid value for defaultSelection +awt.15B=Invalid value for multipleDocumentHandling +awt.15C=Invalid value for attribute sides +awt.15D=Invalid colorspace +awt.15E=Unknown component. Must be REDCOMPONENT, GREENCOMPONENT or BLUECOMPONENT. +awt.15F=Profile class does not comply with ICC specification +awt.160=Color space doesn't comply with ICC specification +awt.161=Unable to open file {0} +awt.162=Invalid ICC Profile Data +awt.163=Can't open color profile +awt.164=Not a predefined color space +awt.165=Color space doesn't comply with ICC specification +awt.166=TRC is not a simple gamma value +awt.167=TRC is a gamma value, not a table +awt.168=Invalid profile class +awt.169=Component index out of range +awt.16A=Invalid component index: {0} +awt.16B=Not a predefined colorspace +awt.16C=Can't load class: {0} +awt.16D=Can't parse MIME type: {0} +awt.16E=Transferable has null data +awt.16F=Can't create reader for this representation class +awt.170=Can't create default D&D cursor: {0} +awt.171=Attempt to start a drag while an existing drag operation is still executing +awt.172=Drag source is null +awt.173=One listener is already exist +awt.174=dgl is not current listener +awt.175=Listener mismatch +awt.176=DropTarget cannot be added as listener to itself +awt.177=Invalid user action +awt.178=Invalid source action +awt.179=Context peer is null +awt.17A=Trigger event is null +awt.17B=Can't init ACTION_NONE drag +awt.17C=Image offset is null +awt.17D=Transferable is null +awt.17E=Component associated with the trigger event is null +awt.17F=DragSource for the trigger event is null +awt.180=Source actions for the DragGestureRecognizer associated with the trigger event are equal to DnDConstants.ACTION_NONE +awt.181=Attempt to register context as its listener +awt.182=dsl is not current listener +awt.183=Invalid status +awt.184=Invalid action +awt.185=Component is null +awt.186=DragSource is null +awt.187=Origin is null +awt.188=Event list is null +awt.189=Event list is empty +awt.18A=Context is null +awt.18B=Invalid button value +awt.18C=Cannot invoke null runnable +awt.18D=Source is null +awt.18E=Wrong event id +awt.18F=Text must be null for CARET_POSITION_CHANGED +awt.190=Wrong committedCharacterCount +awt.191=Invalid keyCode for KEY_TYPED event, must be VK_UNDEFINED +awt.192=Invalid keyChar for KEY_TYPED event, can't be CHAR_UNDEFINED +awt.193=Listener can't be zero +awt.194=Unknown attribute name +awt.195=Offset is out of bounds +awt.196=Justification impossible, layout already justified +awt.197=Endpoints are out of range +awt.198=Illegal alignment argument +awt.199=Illegal range argument value: {0} +awt.19A=start or count arguments are out of text range +awt.19B=count argument must be positive +awt.19C=weight must be a positive number +awt.19D=growLeftLimit must be a positive number +awt.19E=growRightLimit must be a positive number +awt.19F=incorrect value for shrinkPriority, more than PRIORITY_NONE or less than PRIORITY_KASHIDA value +awt.200=incorrect value for growPriority, more than PRIORITY_NONE or less than PRIORITY_KASHIDA value +awt.201=shrinkLeftLimit must be a positive number +awt.202=shrinkRightLimit must be a positive number +awt.203=Offset limit should be greater than current position +awt.204=Determinant is zero +awt.205=Invalid type of Arc: {0} +awt.206=Flatness is less then zero +awt.207=Limit is less then zero +awt.208=Path is null +awt.209=Invalid winding rule value +awt.20A=First segment should be SEG_MOVETO type +awt.20B=unknown input method highlight state +awt.20C=Number of Bits equals to zero +awt.20D=The number of bits per pixel is not a power of 2 or pixels span data element boundaries +awt.20E=Data Bit offset is not a multiple of pixel bit stride +awt.20F=Number of bands must be only 1 +awt.210=The component value for this ColorModel is signed +awt.211=Pixel values for this ColorModel are not conveniently representable as a single int +awt.212=There is more than one component in this ColorModel +awt.213=This ComponentColorModel does not support the unnormalized form +awt.214=This Color Model doesn't support this transferType +awt.215=transferType is not one of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, DataBuffer.TYPE_INT, DataBuffer.TYPE_SHORT, DataBuffer.TYPE_FLOAT, or DataBuffer.TYPE_DOUBLE +awt.216=The components array is not large enough to hold all the color and alpha components +awt.217=The transfer type of this ComponentColorModel is not one of the following transfer types: DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT +awt.218=The components array is not large enough to hold all the color and alpha components +awt.219=This transferType is not supported by this color model +awt.21A=This ComponentColorModel does not support this transferType +awt.21B=The length of normComponents minus normOffset is less than numComponents +awt.21C=The number of scale factors should not be zero +awt.21D=Number of src bands ({0}) does not match number of dst bands ({1}) +awt.21E=Number of scaling constants is not equal to the number of bands +awt.21F=Unable to transform source +awt.220=Source should not have IndexColorModel +awt.221=The imageType is TYPE_BYTE_BINARY and the color map has more than 16 entries +awt.222=The imageType is not TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED +awt.223=The imageType is not compatible with ColorModel +awt.224=Unknown image type +awt.225=Property name is null +awt.226=Both tileX and tileY are not equal to 0 +awt.227=This image type can't have alpha +awt.228=minX or minY of this raster not equal to zero +awt.229=Number of components in the LUT does not match the number of bands +awt.22A=Wrong type of pixels array +awt.22B=Length of data should not be less than width*height +awt.22C=Unknown data type {0} +awt.22D=This transferType ( {0} ) is not supported by this color model +awt.22E=w or h is less than or equal to zero +awt.22F=The product of w and h is greater than Integer.MAX_VALUE +awt.230=dataType is not one of the supported data types +awt.231=Number of bands must be more then 0 +awt.232=Offset should be not less than zero +awt.233=Number of components should be positive +awt.234=Width or Height equals zero +awt.235=Wrong Data Buffer type : {0} +awt.236=The bits is less than 1 or greater than 32 +awt.237=Source and destinations rasters do not have the same number of bands +awt.238=The number of arrays in the LookupTable does not meet the restrictions +awt.239=The space is not a TYPE_RGB space +awt.23A=The min/max normalized component values are not 0.0/1.0 +awt.23B=The mask of the {0} component is not contiguous +awt.23C=The mask of the alpha component is not contiguous +awt.23D=The mask of the red component is not contiguous +awt.23E=The mask of the green component is not contiguous +awt.23F=The mask of the blue component is not contiguous +awt.240=The transferType not is one of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT or DataBuffer.TYPE_INT +awt.241=Any offset between bands is greater than the Scanline stride +awt.242=Pixel stride is less than any offset between bands +awt.243=Product of Pixel stride and w is greater than Scanline stride +awt.244=Width or Height of child Raster is less than or equal to zero +awt.245=parentX disposes outside Raster +awt.246=parentY disposes outside Raster +awt.247=parentX + w results in integer overflow +awt.248=parentY + h results in integer overflow +awt.249=childMinX + w results in integer overflow +awt.24A=childMinY + h results in integer overflow +awt.24B=Pixel stride must be >= 0 +awt.24C=Scanline stride must be >= 0 +awt.24D=Bank Indices length must be equal Bank Offsets length +awt.24E=Index of {0} bank must be >= 0 +awt.24F=Unable to invert transform {0} +awt.250=Unknown interpolation type: {0} +awt.251=Transformed width ({0}) and height ({1}) should be greater than 0 +awt.252=Source can't be same as the destination +awt.253=Different number of bands in source and destination +awt.254=Number of bands in the source raster ({0}) is incompatible with the matrix [{1}x{2}] +awt.255=Number of bands in the destination raster ({0}) is incompatible with the matrix [{1}x{2}] +awt.256=Source raster is null +awt.257=Source raster is equal to destination +awt.258=Number of source bands ({0}) is not equal to number of destination bands ({1}) +awt.259=Source image is null +awt.25A=Source equals to destination +awt.25B=Null ColorSpace passed as a parameter +awt.25C=Null profiles passed as a parameter +awt.25D=Source or destination color space is not defined +awt.25E=Incorrect number of source raster bands. Should be equal to the number of color components of source colorspace. +awt.25F=Incorrect number of destination raster bands. Should be equal to the number of color components of destination colorspace. +awt.260=Incompatible rasters - width or height differs +awt.261=Destination color space is undefined +awt.262=Destionation color space should be defined +awt.263=Incompatible images - width or height differs +awt.264=Size of the color map is less than 1 +awt.265=The raster argument is not compatible with this IndexColorModel +awt.266=The number of bits in a pixel is greater than 16 +awt.267=The transferType is invalid +awt.268=The pixel is not a primitive array of type transferType +awt.269=The transferType is not one of DataBuffer.TYPE_BYTE or DataBuffer.TYPE_USHORT +awt.26A=Incorrect ImageConsumer completion status +awt.26B=The number of bits in the pixel values is less than 1 +awt.26C=bits is null +awt.26D=The elements in bits is less than 0 +awt.26E=The sum of the number of bits in bits is less than 1 +awt.26F=The cspace is null +awt.270=The transparency is not a valid value +awt.271=The number of bits in bits is less than 1 +awt.272=The length of components minus offset is less than numComponents +awt.273=The length of normComponents minus normOffset is less than numComponents +awt.274=componentIdx is greater than the number of components or less than zero +awt.275=This pixel representation is not suuported by tis Color Model +awt.276=location.x + w or location.y + h results in integer overflow +awt.277=bankIndices or bandOffsets is null +awt.278=dataBuffer is null +awt.279=bands is less than 1 +awt.27A=dataBuffer has more than one bank +awt.27B=bandOffsets is null +awt.27C=bandMasks is null +awt.27D=bitsPerBand or bands is not greater than zero +awt.27E=The product of bitsPerBand and bands is greater than the number of bits held by dataType +awt.27F=SampleModel or DataBuffer is null +awt.280=SampleModel is null +awt.281=sampleModel, dataBuffer, aRegion or sampleModelTranslate is null +awt.282=aRegion has width or height less than or equal to zero +awt.283=Overflow X coordinate of Raster +awt.284=Overflow Y coordinate of Raster +awt.285=Width or Height of child Raster is less than or equal to zero +awt.286=parentX disposes outside Raster +awt.287=parentY disposes outside Raster +awt.288=parentX + width results in integer overflow +awt.289=parentY + height results in integer overflow +awt.28A=childMinX + width results in integer overflow +awt.28B=childMinY + height results in integer overflow +awt.28C=Rect is null +awt.28D=Length of dataArray[{0}] is less than size + offset[{1}] +awt.28E=Length of dataArray is less than size + offset +awt.28F=Source and destination rasters do not have the same width! +awt.290=Source and destination rasters do not have the same height! +awt.291=Source and destination images do not have the same width! +awt.292=Source and destination images do not have the same height! +awt.294=pixel is null +awt.295=data is null +awt.296=can't allocate memory on video card to create new display list +awt.297=Invalid keyLocation +awt.298=dataBuffer is too small + +awt.err.00=file dialog {0} error! +awt.err.01=error: {0} +awt.err.02=GDIPlus DrawDriverString error status = {0} +awt.err.03=gdipDrawCompositeGlyphVector: GDIPlus DrawDriverString error status = {0} +awt.err.04=gdipDrawCompositeGlyphVector: GDIPlus DrawDriverString error status = {0} diff --git a/app/src/main/java/org/apache/harmony/awt/state/MenuItemState.java b/app/src/main/java/org/apache/harmony/awt/state/MenuItemState.java new file mode 100644 index 000000000..b13e50bf0 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/state/MenuItemState.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package org.apache.harmony.awt.state; + +import java.awt.Dimension; +import java.awt.Rectangle; + +/** + * State of menu item + */ + +public interface MenuItemState { + + String getText(); + Rectangle getTextBounds(); + void setTextBounds(int x, int y, int w, int h); + + String getShortcut(); + Rectangle getShortcutBounds(); + void setShortcutBounds(int x, int y, int w, int h); + + Rectangle getItemBounds(); + void setItemBounds(int x, int y, int w, int h); + + boolean isMenu(); + boolean isChecked(); + boolean isEnabled(); + + boolean isCheckBox(); + boolean isSeparator(); + + Dimension getMenuSize(); +} diff --git a/app/src/main/java/org/apache/harmony/awt/state/MenuState.java b/app/src/main/java/org/apache/harmony/awt/state/MenuState.java new file mode 100644 index 000000000..564a49a08 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/state/MenuState.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package org.apache.harmony.awt.state; + +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Point; + +/** + * State of pop-up or drop-down menu + */ + +public interface MenuState { + int getWidth(); + int getHeight(); + Point getLocation(); + + void setSize(int w, int h); + + Font getFont(); + boolean isFontSet(); + FontMetrics getFontMetrics(Font f); + + int getItemCount(); + int getSelectedItemIndex(); + + MenuItemState getItem(int index); +} diff --git a/app/src/main/java/org/apache/harmony/awt/state/State.java b/app/src/main/java/org/apache/harmony/awt/state/State.java new file mode 100644 index 000000000..4b8706d13 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/state/State.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package org.apache.harmony.awt.state; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Rectangle; + +/** + * State of the component + */ +public interface State { + + boolean isEnabled(); + boolean isVisible(); + boolean isFocused(); + + Font getFont(); + boolean isFontSet(); + FontMetrics getFontMetrics(); + + Color getBackground(); + boolean isBackgroundSet(); + + Color getTextColor(); + boolean isTextColorSet(); + + Rectangle getBounds(); + Dimension getSize(); + + Dimension getDefaultMinimumSize(); + void setDefaultMinimumSize(Dimension size); + + long getWindowId(); +} diff --git a/app/src/main/java/org/apache/harmony/awt/wtk/CreationParams.java b/app/src/main/java/org/apache/harmony/awt/wtk/CreationParams.java new file mode 100644 index 000000000..63c581df2 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/wtk/CreationParams.java @@ -0,0 +1,133 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Dmitry A. Durnev + * @version $Revision$ + */ +package org.apache.harmony.awt.wtk; + +/** + * This class describes cross-platform NativeWindow creation params + * See also WindowFactory.createWindow + */ +public class CreationParams { + /** + * Initial state is maximized verticaly + */ + public final long MAXIMIZED_VERT = 1; + /** + * Initial state is maximized horizontaly + */ + public final long MAXIMIZED_HORIZ = 2; + /** + * Initial state is maximized both + * horizontaly and verticaly + */ + public final long MAXIMIZED = 3; + + /** + * The top-level window that has all possible decorations, + * has no owner and is displayed in taskbar + */ + public final static int DECOR_TYPE_FRAME = 1; + /** + * The dialog window + */ + public final static int DECOR_TYPE_DIALOG = 2; + /** + * The transient undecorated pop-up window + */ + public final static int DECOR_TYPE_POPUP = 3; + /** + * The undecoraded pop-up window + */ + public final static int DECOR_TYPE_UNDECOR = 4; + /** + * Non-MDI child window + */ + public final static int DECOR_TYPE_NONE = 0; + + /** + * Initial x. + */ + public int x = 0; + /** + * Initial y. + */ + public int y = 0; + /** + * Initial width. + */ + public int w = 1; + /** + * Initial height. + */ + public int h = 1; + /** + * The decoration type of the top-level window. The possible values are: + * DECOR_TYPE_FRAME, DECOR_TYPE_DIALOG, DECOR_TYPE_POPUP and DECOR_TYPE_UNDECOR + */ + public int decorType = DECOR_TYPE_NONE; + /** + * Window is child of parent, otherwise it's + * toplevel(child of desktop) window owned by parent. + */ + public boolean child = false; + /** + * Window is resizable + */ + public boolean resizable = true; + /** + * The window has no decorations + */ + public boolean undecorated = false; + /** + * Initial visibility state. + */ + public boolean visible = false; + /** + * Window is ALWAYS topmost in Z order. + */ + public boolean topmost = false; + /** + * Window is disabled. + */ + public boolean disabled = false; + /** + * Window initially iconified. + */ + public boolean iconified = false; + /** + * Bitwise OR of MAXIMIZED_* constants. + * Means if window is initially maximized. + */ + public int maximizedState = 0; + /** + * Tells that window position should be determined by native windowing system + */ + public boolean locationByPlatform = false; + /** + * Id of parent or owner window, see child field + * For non-child window without owner equals 0. + */ + public long parentId = 0; + /** + * Name wich is displayed on titlebar, taskbar and visible + * for system requests. + */ + public String name = null; +} \ No newline at end of file diff --git a/app/src/main/java/org/apache/harmony/awt/wtk/GraphicsFactory.java b/app/src/main/java/org/apache/harmony/awt/wtk/GraphicsFactory.java new file mode 100644 index 000000000..0d7c84f7b --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/wtk/GraphicsFactory.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov, Alexey A. Petrenko, Oleg V. Khaschansky + * @version $Revision$ + */ +package org.apache.harmony.awt.wtk; + +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.GraphicsEnvironment; +import java.awt.peer.FontPeer; +import org.apache.harmony.awt.gl.MultiRectArea; +import org.apache.harmony.awt.gl.font.FontManager; + +import android.graphics.Canvas; +import android.graphics.Paint; + + +/** + * GraphicsFactory interface defines methods for Graphics2D + * and font stuff instances factories. + */ +public interface GraphicsFactory { + static final FontMetrics cacheFM[] = new FontMetrics[10]; + + /** + * This method creates Graphics2D instance for specified native window. + * + * @param win Native window to draw + * @param translateX Translation along X axis + * @param translateY Translation along Y axis + * @param clip Clipping area for a new Graphics2D instance + * @return New Graphics2D instance for specified native window + * @deprecated + */ + @Deprecated + Graphics2D getGraphics2D(NativeWindow win, int translateX, int translateY, MultiRectArea clip); + + /** + * This method creates Graphics2D instance for specified native window. + * + * @param win Native window to draw + * @param translateX Translation along X axis + * @param translateY Translation along Y axis + * @param width Width of drawing area + * @param height Height of drawing area + * @return New Graphics2D instance for specified native window + */ + Graphics2D getGraphics2D(NativeWindow win, int translateX, int translateY, int width, int height); + // ???AWT: not standard harmony + Graphics2D getGraphics2D(Canvas c, Paint p); + + /** + * Creates instance of GraphicsEnvironment for specified WindowFactory + * + * @param wf WindowFactory + * @return New instance of GraphicsEnvironment + */ + GraphicsEnvironment createGraphicsEnvironment(WindowFactory wf); + + // Font methods + FontMetrics getFontMetrics(Font font); + FontManager getFontManager(); + FontPeer getFontPeer(Font font); + Font embedFont(String fontFilePath); +} diff --git a/app/src/main/java/org/apache/harmony/awt/wtk/KeyInfo.java b/app/src/main/java/org/apache/harmony/awt/wtk/KeyInfo.java new file mode 100644 index 000000000..1f8a29aa0 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/wtk/KeyInfo.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package org.apache.harmony.awt.wtk; + +import java.awt.event.KeyEvent; + +/** + * Keystroke information + */ + +public final class KeyInfo { + + public int vKey; + public int keyLocation; + public final StringBuffer keyChars; + + public static final int DEFAULT_VKEY = KeyEvent.VK_UNDEFINED; + public static final int DEFAULT_LOCATION = KeyEvent.KEY_LOCATION_STANDARD; + + public KeyInfo() { + vKey = DEFAULT_VKEY; + keyLocation = DEFAULT_LOCATION; + keyChars = new StringBuffer(); + } + + public void setKeyChars(char ch) { + keyChars.setLength(0); + keyChars.append(ch); + } + + public void setKeyChars(StringBuffer sb) { + keyChars.setLength(0); + keyChars.append(sb); + } +} diff --git a/app/src/main/java/org/apache/harmony/awt/wtk/NativeEvent.java b/app/src/main/java/org/apache/harmony/awt/wtk/NativeEvent.java new file mode 100644 index 000000000..1471c1a72 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/wtk/NativeEvent.java @@ -0,0 +1,268 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Mikhail Danilov + * @version $Revision$ + */ +package org.apache.harmony.awt.wtk; + +import java.awt.Insets; +import java.awt.Rectangle; +import java.awt.Point; +import java.awt.event.KeyEvent; + +import org.apache.harmony.awt.gl.MultiRectArea; + + +/** + * The interface describing cross-platform translation of system + * messages. + * + *

    Some messages can appear only on specific platform, + * but they still can have cross-platform interpretation if the + * application should be aware of them and can react using + * cross-platform API. + * + */ +public abstract class NativeEvent { + + /** + * Message has no common cross-platform + * interpretation and should be skipped. + */ + public static final int ID_PLATFORM = 0; + + /** + * Window bounds have changed. + */ + public static final int ID_BOUNDS_CHANGED = -1; + + /** + * Window decoration size has changed. + */ + public static final int ID_INSETS_CHANGED = -2; + + /** + * Window was just created (WM_CREATE on Windows) + */ + public static final int ID_CREATED = -3; + + /** + * Mouse grab was canceled by the native system + */ + public static final int ID_MOUSE_GRAB_CANCELED = -4; + + /** + * System color scheme or visual theme was changed + */ + public static final int ID_THEME_CHANGED = -5; + + protected long windowId; + protected int eventId; + protected long otherWindowId; + + protected Point screenPos; + protected Point localPos; + protected Rectangle windowRect; + + protected int modifiers; + protected int mouseButton; + protected int wheelRotation; + + protected KeyInfo keyInfo = new KeyInfo(); + + protected int windowState = -1; + protected long time; + + /** + * Returns the system window id of the event recipient. + * @return HWND on Windows, xwindnow on X + */ + public long getWindowId() { + return windowId; + } + + /** + * Returns cross-platform event id + * should be one of ID_* constants or + * id constants from java.awt.AWTEvent subclasess + * @return cross-platform event id + */ + public int getEventId() { + return eventId; + } + + /** + * Returns the position of cursor when event occured relative to + * top-left corner of recipient window + * @return position of cursor in local coordinates + */ + public Point getLocalPos() { + return localPos; + } + + /** + * Returns the position of cursor when event occured + * in screen coordinates. + * @return position of cursor in screen coordinates + */ + public Point getScreenPos() { + return screenPos; + } + + /** + * The recipient window bounds when the event occured + * @return window bounds + */ + public Rectangle getWindowRect() { + return windowRect; + } + + /** + * Returns the state of keyboard and mouse buttons when the event + * occured if event from mouse or keyboard, for other events can + * return junk values. The value is bitwise OR of + * java.awt.event.InputEvent *_DOWN constants. + * + * Method is aware of system mouse button swap for left-hand + * mouse and return swapped values. + * @return bitwise OR of java.awt.event.InputEvent *_DOWN constants + */ + public int getInputModifiers() { + return modifiers; + } + + /** + * Returns the iconified/maximized state of recipient window if + * event is state related, for other events can junk values. + * The value has the same meaning as Frame.getExtendedState + * It's bitwise OR of ICONIFIED, MAXIMIZED_HORIZ, MAXIMIZED_VERT + * @return bitwise OR of ICONIFIED, MAXIMIZED_HORIZ, MAXIMIZED_VERT + */ + public int getWindowState() { + return windowState; + } + + /** + * The same meaning as java.awt.event.getKeyCode + * @return java.awt.event VK_* constant + */ + public int getVKey() { + return (keyInfo != null) ? keyInfo.vKey : KeyInfo.DEFAULT_VKEY; + } + + /** + * The same meaning as java.awt.event.getKeyLocation + * @return java.awt.event KEY_LOCATION_* constant + */ + public int getKeyLocation() { + return (keyInfo != null) ? keyInfo.keyLocation : KeyInfo.DEFAULT_LOCATION; + } + + /** + * Return the string of characters associated with the event + * Has meaning only for KEY_PRESSED as should be translated to + * serie of KEY_TYPED events. For dead keys and input methods + * one key press can generate multiple key chars. + * @return string of characters + */ + public StringBuffer getKeyChars() { + if (keyInfo == null) { + return null; + } + if (keyInfo.vKey == KeyEvent.VK_ENTER) { + keyInfo.keyChars.setLength(0); + keyInfo.setKeyChars('\n'); + } + return keyInfo.keyChars; + } + + public char getLastChar() { + if (keyInfo == null || keyInfo.keyChars.length() == 0) { + return KeyEvent.CHAR_UNDEFINED; + } + return keyInfo.keyChars.charAt(keyInfo.keyChars.length()-1); + } + + /** + * Returns the number of mouse button which changed it's state, + * otherwise 0. + * Left button is 1, middle button is 2, right button is 3. + * + * Method is aware of system mouse button swap for left-hand + * mouse and return swapped values. + * @return mouse button number + */ + public int getMouseButton() { + return mouseButton; + } + + /** + * Returns time when the message was received + * @return time in milliseconds + */ + public long getTime() { + return time; + } + + /** + * For the focus event contains the oposite window. + * This means it lost focus if recipient gains it, + * or will gain focus if recipient looses it. + * @return HWND on Windows, xwindnow on X + */ + public long getOtherWindowId() { + return otherWindowId; + } + + /** + * Returns the "dirty" area of the window as set of non-intersecting + * rectangles. This area is to be painted. + * @return non-empty array of null if empty + */ + public abstract MultiRectArea getClipRects(); + + /** + * Returns the "dirty" area of the window as one rectangle. + * This area is to be painted. + * @return non-null Rectangle + */ + public abstract Rectangle getClipBounds(); + + /** + * Returns the window insets. Insets is area which belongs to + * window somehow but is outside of it's client area, + * it usually contains system provided border and titlebar. + * @return non-null java.awt.Insets + */ + public abstract Insets getInsets(); + + /** + * Returns true if event is popup menu trigger. + * @return boolean flag + */ + public abstract boolean getTrigger(); + + /** + * Returns the number of "clicks" the mouse wheel was rotated. + * @return negative values if the mouse wheel was rotated up/away from the user, + * and positive values if the mouse wheel was rotated down/ towards the user + */ + public int getWheelRotation() { + return wheelRotation; + } +} diff --git a/app/src/main/java/org/apache/harmony/awt/wtk/NativeEventQueue.java b/app/src/main/java/org/apache/harmony/awt/wtk/NativeEventQueue.java new file mode 100644 index 000000000..0738cd138 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/wtk/NativeEventQueue.java @@ -0,0 +1,117 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Mikhail Danilov + * @version $Revision$ + */ +package org.apache.harmony.awt.wtk; + +import java.util.LinkedList; + + +/** + * Describes the cross-platform native event queue interface + * + *

    The implementation constructor should remember thread it was + * created. All other methods would be called obly from this thread, + * except awake(). + */ +public abstract class NativeEventQueue { + + private ShutdownWatchdog shutdownWatchdog; + private class EventMonitor {} + private final Object eventMonitor = new EventMonitor(); + private final LinkedList eventQueue = new LinkedList(); + + public static abstract class Task { + public volatile Object returnValue; + + public abstract void perform(); + } + + /** + * Blocks current thread until native event queue is not empty + * or awaken from other thread by awake(). + * + *

    Should be called only on tread which + * will process native events. + * + * @return if event loop should be stopped + */ + public abstract boolean waitEvent(); + + /** + * Determines whether or not the native event queue is empty. + * An queue is empty if it contains no messages waiting. + * + * @return true if the queue is empty; false otherwise + */ + public boolean isEmpty() { + synchronized(eventQueue) { + return eventQueue.isEmpty(); + } + } + + public NativeEvent getNextEvent() { + synchronized (eventQueue) { + if (eventQueue.isEmpty()) { + shutdownWatchdog.setNativeQueueEmpty(true); + return null; + } + return eventQueue.remove(0); + } + } + + protected void addEvent(NativeEvent event) { + synchronized (eventQueue) { + eventQueue.add(event); + shutdownWatchdog.setNativeQueueEmpty(false); + } + synchronized (eventMonitor) { + eventMonitor.notify(); + } + } + + public final Object getEventMonitor() { + return eventMonitor; + } + + public abstract void awake(); + + /** + * Gets AWT system window ID. + * + * @return AWT system window ID + */ + public abstract long getJavaWindow(); + + /** + * Add NativeEvent to the queue + */ + public abstract void dispatchEvent(); + + public abstract void performTask(Task task); + + public abstract void performLater(Task task); + + public final void setShutdownWatchdog(ShutdownWatchdog watchdog) { + synchronized (eventQueue) { + shutdownWatchdog = watchdog; + } + } + +} diff --git a/app/src/main/java/org/apache/harmony/awt/wtk/NativeEventThread.java b/app/src/main/java/org/apache/harmony/awt/wtk/NativeEventThread.java new file mode 100644 index 000000000..d50add4e3 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/wtk/NativeEventThread.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package org.apache.harmony.awt.wtk; + + +/** + * NativeEventThread + */ +public class NativeEventThread extends Thread { + + public interface Init { + WTK init(); + } + + NativeEventQueue nativeQueue; + Init init; + + private WTK wtk; + + public NativeEventThread() { + super("AWT-NativeEventThread"); //$NON-NLS-1$ + setDaemon(true); + } + + @Override + public void run() { + synchronized (this) { + try { + wtk = init.init(); + nativeQueue = wtk.getNativeEventQueue(); + } finally { + notifyAll(); + } + } + + runModalLoop(); + } + + void runModalLoop() { + while (nativeQueue.waitEvent()) { + nativeQueue.dispatchEvent(); + } + } + + public void start(Init init) { + synchronized (this) { + this.init = init; + super.start(); + try { + wait(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + } + + public WTK getWTK() { + return wtk; + } +} diff --git a/app/src/main/java/org/apache/harmony/awt/wtk/NativeIM.java b/app/src/main/java/org/apache/harmony/awt/wtk/NativeIM.java new file mode 100644 index 000000000..1626f4a9a --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/wtk/NativeIM.java @@ -0,0 +1,130 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Dmitry A. Durnev + * @version $Revision$ + */ +package org.apache.harmony.awt.wtk; + +import java.awt.AWTEvent; +import java.awt.AWTException; +import java.awt.Image; +import java.awt.Rectangle; +import java.awt.im.spi.InputMethod; +import java.awt.im.spi.InputMethodContext; +import java.awt.im.spi.InputMethodDescriptor; +import java.lang.Character.Subset; +import java.util.Locale; + +/** + * A cross-platform interface for native input + * method sub-system functionality. + */ +public abstract class NativeIM implements InputMethod, InputMethodDescriptor { + protected InputMethodContext imc; + + public void activate() { + + } + + public void deactivate(boolean isTemporary) { + + } + + public void dispatchEvent(AWTEvent event) { + + } + + public void dispose() { + + } + + public void endComposition() { + + } + + public Object getControlObject() { + return null; + } + + public Locale getLocale() { + return null; + } + + public void hideWindows() { + + } + + public boolean isCompositionEnabled() { + return false; + } + + public void notifyClientWindowChange(Rectangle bounds) { + + } + + public void reconvert() { + + } + + public void removeNotify() { + + } + + public void setCharacterSubsets(Subset[] subsets) { + + } + + public void setCompositionEnabled(boolean enable) { + + } + + public void setInputMethodContext(InputMethodContext context) { + imc = context; + } + + public boolean setLocale(Locale locale) { + return false; + } + + public Locale[] getAvailableLocales() throws AWTException { + return new Locale[]{Locale.getDefault(), Locale.ENGLISH}; + //return new Locale[]{Locale.getDefault(), Locale.US}; + } + + public InputMethod createInputMethod() throws Exception { + return this; + } + + public String getInputMethodDisplayName(Locale inputLocale, + Locale displayLanguage) { + return "System input methods"; //$NON-NLS-1$ + } + + public Image getInputMethodIcon(Locale inputLocale) { + return null; + } + + public boolean hasDynamicLocaleList() { + return false; + } + + public abstract void disableIME(); + +// public abstract void disableIME(long id); + +} diff --git a/app/src/main/java/org/apache/harmony/awt/wtk/NativeMouseInfo.java b/app/src/main/java/org/apache/harmony/awt/wtk/NativeMouseInfo.java new file mode 100644 index 000000000..06969756b --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/wtk/NativeMouseInfo.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Dmitry A. Durnev + * @version $Revision$ + */ +package org.apache.harmony.awt.wtk; + +import java.awt.Point; + +/** + * The interface provides access to platform dependent functionality + * for classes java.awt.PointerInfo & java.awt.MouseInfo. + */ +public interface NativeMouseInfo { + + /** + * Returns the Point that represents + * the coordinates of the pointer on the screen. + */ + Point getLocation(); + + /** + * Returns the number of buttons on the mouse. + * If no mouse is installed returns -1. + */ + int getNumberOfButtons(); +} diff --git a/app/src/main/java/org/apache/harmony/awt/wtk/NativeRobot.java b/app/src/main/java/org/apache/harmony/awt/wtk/NativeRobot.java new file mode 100644 index 000000000..0b354d05b --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/wtk/NativeRobot.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Dmitry A. Durnev + * @version $Revision$ + */ +package org.apache.harmony.awt.wtk; + +import java.awt.Color; +import java.awt.Rectangle; +import java.awt.image.BufferedImage; + +/** + * A cross-platform interface for java.awt.Robot implementation + */ +public interface NativeRobot { + + /** + * @see java.awt.Robot#createScreenCapture(Rectangle) + * @param screenRect rectangle to capture in screen coordinates + * @return the captured image or null if + * capture failed. + */ + BufferedImage createScreenCapture(Rectangle screenRect); + + /** + * @see java.awt.Robot#getPixelColor(int, int) + */ + Color getPixel(int x, int y); + + /** + * Generate a native system keyboard input event. + * @param keycode A Java virtual key code + * @param press A key is pressed if true, released otherwise + * @see java.awt.Robot#keyPress(int) + * @throws IllegalArgumentException if keycode is invalid in the native system + */ + void keyEvent(int keycode, boolean press); + + /** + * Generate a native system mouse button(s) press or release event. + * @param buttons A mask of Java mouse button flags + * @param press buttons are pressed if true, released otherwise + * @see java.awt.Robot#mousePress(int) + */ + void mouseButton(int buttons, boolean press); + + /** + * Generate a native system mouse motion event. + * + * @see java.awt.Robot#mouseMove(int, int) + */ + void mouseMove(int x, int y); + + /** + * Generate a native system mouse wheel event. + * + * @see java.awt.Robot#mouseWheel(int) + */ + void mouseWheel(int wheelAmt); +} diff --git a/app/src/main/java/org/apache/harmony/awt/wtk/NativeWindow.java b/app/src/main/java/org/apache/harmony/awt/wtk/NativeWindow.java index cda9d8ffe..73fd6c00b 100644 --- a/app/src/main/java/org/apache/harmony/awt/wtk/NativeWindow.java +++ b/app/src/main/java/org/apache/harmony/awt/wtk/NativeWindow.java @@ -25,7 +25,7 @@ import java.awt.Insets; import java.awt.Point; import java.awt.Rectangle; -// import org.apache.harmony.awt.gl.MultiRectArea; +import org.apache.harmony.awt.gl.MultiRectArea; /** @@ -216,5 +216,5 @@ public interface NativeWindow { */ void setIMStyle(); - // MultiRectArea getObscuredRegion(Rectangle part); + MultiRectArea getObscuredRegion(Rectangle part); } diff --git a/app/src/main/java/org/apache/harmony/awt/wtk/ShutdownThread.java b/app/src/main/java/org/apache/harmony/awt/wtk/ShutdownThread.java new file mode 100644 index 000000000..701eb46ca --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/wtk/ShutdownThread.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Michael Danilov, Pavel Dolgov + * @version $Revision$ + */ +package org.apache.harmony.awt.wtk; + +import org.apache.harmony.awt.internal.nls.Messages; + +public final class ShutdownThread extends Thread { + + public static final class Watchdog { + } + + public ShutdownThread() { + setName("AWT-Shutdown"); //$NON-NLS-1$ + setDaemon(false); + } + + private boolean shouldStop = false; + + @Override + public void run() { + synchronized (this) { + notifyAll(); // synchronize the startup + + while (true) { + try { + wait(); + } catch (InterruptedException e) { + } + + if (shouldStop) { + notifyAll(); // synchronize the shutdown + return; + } + } + } + } + + @Override + public void start() { + synchronized (this) { + super.start(); + try { + wait(); + } catch (InterruptedException e) { + // awt.26=Shutdown thread was interrupted while starting + throw new RuntimeException( + Messages.getString("awt.26")); //$NON-NLS-1$ + } + } + } + + public void shutdown() { + synchronized (this) { + shouldStop = true; + notifyAll(); + try { + wait(); + } catch (InterruptedException e) { + // awt.27=Shutdown thread was interrupted while stopping + throw new RuntimeException( + Messages.getString("awt.27")); //$NON-NLS-1$ + } + } + } +} diff --git a/app/src/main/java/org/apache/harmony/awt/wtk/ShutdownWatchdog.java b/app/src/main/java/org/apache/harmony/awt/wtk/ShutdownWatchdog.java new file mode 100644 index 000000000..6efa519fc --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/wtk/ShutdownWatchdog.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package org.apache.harmony.awt.wtk; + +/** + * Shutdown Watchdog + */ +public final class ShutdownWatchdog { + + private boolean nativeQueueEmpty = true; + private boolean awtQueueEmpty = true; + private boolean windowListEmpty = true; + + private boolean forcedShutdown = false; + + private ShutdownThread thread; + + public synchronized void setNativeQueueEmpty(boolean empty) { + nativeQueueEmpty = empty; + checkShutdown(); + } + + public synchronized void setAwtQueueEmpty(boolean empty) { + awtQueueEmpty = empty; + checkShutdown(); + } + + public synchronized void setWindowListEmpty(boolean empty) { + windowListEmpty = empty; + checkShutdown(); + } + + public synchronized void forceShutdown() { + forcedShutdown = true; + shutdown(); + } + + public synchronized void start() { + keepAlive(); + } + + private void checkShutdown() { + if (canShutdown()) { + shutdown(); + } else { + keepAlive(); + } + } + + private boolean canShutdown() { + return (nativeQueueEmpty && awtQueueEmpty && windowListEmpty) || + forcedShutdown; + } + + private void keepAlive() { + if (thread == null) { + thread = new ShutdownThread(); + thread.start(); + } + } + + private void shutdown() { + if (thread != null) { + thread.shutdown(); + thread = null; + } + } +} diff --git a/app/src/main/java/org/apache/harmony/awt/wtk/Synchronizer.java b/app/src/main/java/org/apache/harmony/awt/wtk/Synchronizer.java new file mode 100644 index 000000000..3eeaa0b07 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/wtk/Synchronizer.java @@ -0,0 +1,200 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Mikhail Danilov + * @version $Revision$ + */ +package org.apache.harmony.awt.wtk; + +import java.util.Hashtable; +import java.util.LinkedList; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * Class synchronizer is to protect AWT state integrity in multithreading environment. + * It is supposed to have a child class per native platform. + * The only instance is created on the first use of one of the core AWT classes. + * Registers WTK on the dispatch thread startup. + * It is just a special kind of mutex. + * + */ + +public class Synchronizer { + //TODO: think about java.util.concurrent use for faster blocking/awaking operations + //TODO: think about all synchronized methods. Is there need to synchronize everything? + + /** + * This field holds the counter of lock operation. + * To free synchronizer unlock method must be called $acquestCounter times. + * Equals to 0 when synchronizer is free. + */ + protected int acquestCounter; + + /** + * This field holds the owner of synchronizer. + * Owner of synchronizer is a last thread that successfully locked synchronizer and + * still havn't freed it. Equals to null when synchronizer is free. + */ + protected Thread owner; + + /** + * This field holds the wait queue. + * Wait queue is a queue where thread wait for synchronizer access. + * Empty when synchronizer is free. + */ + protected final LinkedList waitQueue = new LinkedList(); + + /** + * The event dispatch thread + */ + protected Thread dispatchThread; + + private final Hashtable storedStates = new Hashtable(); + + /** + * Acquire the lock for this synchronizer. Nested lock is supported. + * If the mutex is already locked by another thread, the current thread will be put + * into wait queue until the lock becomes available. + * All user threads are served in FIFO order. Dispatch thread has higher priority. + * Supposed to be used in Toolkit.lockAWT() only. + */ + public void lock() { + synchronized (this) { + Thread curThread = Thread.currentThread(); + + if (acquestCounter == 0) { + acquestCounter = 1; + owner = curThread; + } else { + if (owner == curThread) { + acquestCounter++; + } else { + if (curThread == dispatchThread) { + waitQueue.addFirst(curThread); + } else { + waitQueue.addLast(curThread); + } + try { + wait(); + } catch (InterruptedException e) { + if (owner != curThread) { + waitQueue.remove(curThread); + // awt.1F=Waiting for resource access thread interrupted not from unlock method. + throw new RuntimeException(Messages + .getString("awt.1F")); //$NON-NLS-1$ + } + } + } + } + } + } + + /** + * Release the lock for this synchronizer. + * If wait queue is not empty the first waiting thread acquires the lock. + * Supposed to be used in Toolkit.unlockAWT() only. + */ + public void unlock() { + synchronized (this) { + if (acquestCounter == 0) { + // awt.20=Can't unlock not locked resource. + throw new RuntimeException(Messages.getString("awt.20")); //$NON-NLS-1$ + } + if (owner != Thread.currentThread()) { + // awt.21=Not owner can't unlock resource. + throw new RuntimeException(Messages.getString("awt.21")); //$NON-NLS-1$ + } + + acquestCounter--; + if (acquestCounter == 0) { + if (waitQueue.size() > 0) { + acquestCounter = 1; + owner = waitQueue.removeFirst(); + owner.interrupt(); + } else { + owner = null; + } + } + } + } + + /** + * Stores state of this synchronizer and frees it. + * Supposed to be used in Toolkit.unsafeInvokeAndWaitUnderAWTLock() only in pair with + * lockAndRestoreState(). + * Do not call it directly. + */ + public void storeStateAndFree() { + synchronized (this) { + Thread curThread = Thread.currentThread(); + + if (owner != curThread) { + // awt.22=Not owner can't free resource. + throw new RuntimeException(Messages.getString("awt.22")); //$NON-NLS-1$ + } + if (storedStates.containsKey(curThread)) { + // awt.23=One thread can't store state several times in a row. + throw new RuntimeException(Messages.getString("awt.23")); //$NON-NLS-1$ + } + + storedStates.put(curThread, new Integer(acquestCounter)); + acquestCounter = 1; + unlock(); + } + } + + /** + * Locks this synchronizer and restores it's state. + * Supposed to be used in Toolkit.unsafeInvokeAndWaitUnderAWTLock() only in pair with + * storeStateAndFree(). + * Do not call it directly. + */ + public void lockAndRestoreState() { + synchronized (this) { + Thread curThread = Thread.currentThread(); + + if (owner == curThread) { + // awt.24=Owner can't overwrite resource state. Lock operations may be lost. + throw new RuntimeException( + Messages.getString("awt.24")); //$NON-NLS-1$ + } + if (!storedStates.containsKey(curThread)) { + // awt.25=No state stored for current thread. + throw new RuntimeException(Messages.getString("awt.25")); //$NON-NLS-1$ + } + + lock(); + acquestCounter = storedStates.get(curThread).intValue(); + storedStates.remove(curThread); + } + } + + /** + * Sets references to WTK and event dispatch thread. + * Called on toolkit startup. + * + * @param wtk - reference to WTK instance + * @param dispatchThread - reference to event dispatch thread + */ + public void setEnvironment(WTK wtk, Thread dispatchThread) { + synchronized (this) { + this.dispatchThread = dispatchThread; + } + } + +} diff --git a/app/src/main/java/org/apache/harmony/awt/wtk/SystemProperties.java b/app/src/main/java/org/apache/harmony/awt/wtk/SystemProperties.java new file mode 100644 index 000000000..6b59f0e70 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/wtk/SystemProperties.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package org.apache.harmony.awt.wtk; + +import java.awt.Font; +import java.awt.font.TextAttribute; +import java.awt.im.InputMethodHighlight; +import java.util.Map; + +/** + * NativeProperties + */ + +public interface SystemProperties { + + /** + * Get current value of a system color + * @param index - one of java.awt.SystemColor constants + * @return ARGB value of requested system color + */ + int getSystemColorARGB(int index); + + /** + * Get default font for GUI elements such as menus and buttons + * @return the font object + */ + Font getDefaultFont(); + + /** + * Fill the given Map with system properties + */ + void init(Map desktopProperties); + + /** + * Fills the given map with system-dependent visual text + * attributes for the abstract description + * of the given input method highlight + * @see java.awt.Toolkit.mapInputMethodHighlight() + */ + void mapInputMethodHighlight(InputMethodHighlight highlight, Map map); +} diff --git a/app/src/main/java/org/apache/harmony/awt/wtk/WTK.java b/app/src/main/java/org/apache/harmony/awt/wtk/WTK.java new file mode 100644 index 000000000..4162fbd52 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/wtk/WTK.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Pavel Dolgov + * @version $Revision$ + */ +package org.apache.harmony.awt.wtk; + +import java.awt.GraphicsDevice; + + +public abstract class WTK { + + public abstract GraphicsFactory getGraphicsFactory(); + public abstract NativeEventQueue getNativeEventQueue(); + public abstract WindowFactory getWindowFactory(); + + /** + * Returns platform specific implementation of the interface + * org.apache.harmony.awt.wtk.CursorFactory. + * @return implementation of CursorFactory + */ + public abstract CursorFactory getCursorFactory(); + + /** + * Returns platform specific implementation of the interface + * org.apache.harmony.awt.wtk.NativeMouseInfo. + * @return implementation of NativeMouseInfo + */ + public abstract NativeMouseInfo getNativeMouseInfo(); + + public abstract SystemProperties getSystemProperties(); + + /** + * Returns platform specific implementation of the interface + * org.apache.harmony.awt.wtk.NativeRobot. + * @return implementation of NativeRobot + */ + public abstract NativeRobot getNativeRobot(GraphicsDevice screen); + + /** + * Returns platform specific implementation of the abstract + * class org.apache.harmony.awt.wtk.NativeIM. + * @return implementation of NativeIM + */ + public abstract NativeIM getNativeIM(); +} diff --git a/app/src/main/java/org/apache/harmony/awt/wtk/WindowFactory.java b/app/src/main/java/org/apache/harmony/awt/wtk/WindowFactory.java new file mode 100644 index 000000000..23604dad4 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/awt/wtk/WindowFactory.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Mikhail Danilov + * @version $Revision$ + */ +package org.apache.harmony.awt.wtk; + +import java.awt.Dimension; +import java.awt.Point; + +/** + * Provides factory for NativeWindow + */ +public interface WindowFactory { + /** + * Creates and returns NativeWindow with desired + * creation params + * + * @param p - initial window properties + * @return created window + */ + NativeWindow createWindow(CreationParams p); + /** + * Create NativeWindow instance connected to existing native resource + * @param nativeWindowId - id of existing window + * @return created NativeWindow instance + */ + NativeWindow attachWindow(long nativeWindowId); + /** + * Returns NativeWindow instance if created by this instance of + * WindowFactory, otherwise null + * + * @param id - HWND on Windows xwindow on X + * @return NativeWindow or null if unknown + */ + NativeWindow getWindowById(long id); + /** + * Returns NativeWindow instance of the top-level window + * that contains a specified point and was + * created by this instance of WindowFactory + * @param p - Point to check + * @return NativeWindow or null if the point is + * not within a window created by this WindowFactory + */ + NativeWindow getWindowFromPoint(Point p); + + /** + * Returns whether native system supports the state for windows. + * This method tells whether the UI concept of, say, maximization or iconification is supported. + * It will always return false for "compound" states like Frame.ICONIFIED|Frame.MAXIMIZED_VERT. + * In other words, the rule of thumb is that only queries with a single frame state + * constant as an argument are meaningful. + * + * @param state - one of named frame state constants. + * @return true is this frame state is supported by this Toolkit implementation, false otherwise. + */ + boolean isWindowStateSupported(int state); + + /** + * @see org.apache.harmony.awt.ComponentInternals + */ + void setCaretPosition(int x, int y); + + /** + * Request size of arbitrary native window + * @param id - window ID + * @return window size + */ + Dimension getWindowSizeById(long id); +} \ No newline at end of file diff --git a/app/src/main/java/org/apache/harmony/beans/internals/nls/messages.properties b/app/src/main/java/org/apache/harmony/beans/internals/nls/messages.properties new file mode 100644 index 000000000..72b1c8cad --- /dev/null +++ b/app/src/main/java/org/apache/harmony/beans/internals/nls/messages.properties @@ -0,0 +1,103 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# messages for EN locale +beans.00=no getter for {0} property +beans.01=no property for name {0} is found +beans.02=in DefaultPersistenceDelegate.mutatesTo() {0} : {1} +beans.03=Target Bean class is null +beans.04=bad property name +beans.05=Modifier for setter method should be public. +beans.06=Number of parameters in setter method is not equal to 1. +beans.07=Parameter type in setter method does not corresponds to predefined. +beans.08=Number of parameters in getter method is not equal to 0. +beans.09=Parameter type in getter method does not corresponds to predefined. +beans.0A=Modifier for getter method should be public. +beans.0B=Exception in command execution +beans.0C=source is null +beans.0D=Error in expression: {0} +beans.0E=Changes are null +beans.0F=The new BeanContext can not be set +beans.10=no node is found for statement with target = {0} +beans.11=no getter for property {0} found +beans.12=cannot access property {0} getter +beans.13=no setter for property {0} found +beans.14=Exception while finding property descriptor +beans.15=The listener is null +beans.16=The provider is null +beans.17=The child is null +beans.18=The requestor is null +beans.19=The service class is null +beans.1A=The service selector is null +beans.1B=The service is null +beans.1C=The event is null +beans.1D=bean is null +beans.1E=Illegal class name: {0} +beans.1F=Method not found: get{0} +beans.20=Method not found: set{0} +beans.21=Modifier for indexed getter method should be public. +beans.22=Number of parameters in getter method is not equal to 1. +beans.23=Parameter in indexed getter method is not of integer type. +beans.24=Parameter type in indexed getter method does not correspond to predefined. +beans.25=Modifier for indexed setter method should be public. +beans.26=Number of parameters in indexed setter method is not equal to 2. +beans.27=First parameter type in indexed setter method should be int. +beans.28=Second parameter type in indexed setter method does not corresponds to predefined. +beans.29=Membership listener is null +beans.2A=Target child can not be null +beans.2B=Resource name can not be null +beans.2C=The child can not be null +beans.2D=Invalid resource +beans.2E=PropertyVetoException was thrown while removing a child: {0}; Original error message:{1} +beans.2F=Target child is null +beans.30=PropertyVetoException was thrown while adding a child: {0}; Original error message:{1} +beans.31=No valid method {0} for {1} found. +beans.32=Cannot acquire event type from {0} listener. +beans.33={0} does not return +beans.34={0} should have a single input parameter +beans.35=Single parameter does not match to {0} class +beans.36=No input params are allowed for getListenerMethod +beans.37=Return type of getListenerMethod is not an array of listeners +beans.38=Add and remove methods are not available +beans.39=Cannot generate event set descriptor for name {0}. +beans.3A=Event type with name {0} is not found. +beans.3B=skipping expression {0}... +beans.3C=Unknown method name for array +beans.3D=First parameter in array getter(setter) is not of Integer type +beans.3E=Illegal number of arguments in array getter +beans.3F=Illegal number of arguments in array setter +beans.40=No constructor for class {0} found +beans.41=No method with name {0} is found +beans.42=target is not generated: classname {0} is not found +beans.43=Cannot convert {0} to char +beans.44=for property {0} no getter(setter) is found +beans.45=method name is not generated: error in getMethodName() +beans.46=Not a valid child +beans.47=Unable to instantiate property editor +beans.48=Property editor is not assignable from the PropertyEditor interface +beans.49=Child cannot implement both BeanContextChild and BeanContextProxy +beans.4A=newInstance is null +beans.4B=type is null +beans.4C=encoder is null +beans.4D=Invalid method call +beans.4E=stopClass is not ancestor of beanClass +beans.4F=search path is null +beans.50=not an indexed property +beans.51=Listener method {0} should have parameter of type {1} +beans.52=listenerMethodName(s) is null +beans.53=eventSetName is null +beans.54=listenerType is null +beans.55=Method is null diff --git a/app/src/main/java/org/apache/harmony/security/fortress/Services.java b/app/src/main/java/org/apache/harmony/security/fortress/Services.java new file mode 100644 index 000000000..ce40203b5 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/security/fortress/Services.java @@ -0,0 +1,197 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.harmony.security.fortress; +import java.security.Provider; +import java.security.Security; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Locale; +/** + * This class contains information about all registered providers and preferred + * implementations for all "serviceName.algName". + */ +public class Services { + /** + * The HashMap that contains information about preferred implementations for + * all serviceName.algName in the registered providers. + * Set the initial size to 600 so we don't grow to 1024 by default because + * initialization adds a few entries more than the growth threshold. + */ + private static final HashMap> services + = new HashMap>(600); + /** + * Save default SecureRandom service as well. + * Avoids similar provider/services iteration in SecureRandom constructor. + */ + private static Provider.Service cachedSecureRandomService; + /** + * Need refresh flag. + */ + private static boolean needRefresh; + /** + * The cacheVersion is changed on every update of service + * information. It is used by external callers to validate their + * own caches of Service information. + */ + private static int cacheVersion = 1; + /** + * Registered providers. + */ + private static final ArrayList providers = new ArrayList(20); + /** + * Hash for quick provider access by name. + */ + private static final HashMap providersNames + = new HashMap(20); + static { + String providerClassName = null; + int i = 1; + ClassLoader cl = ClassLoader.getSystemClassLoader(); + while ((providerClassName = Security.getProperty("security.provider." + i++)) != null) { + try { + Class providerClass = Class.forName(providerClassName.trim(), true, cl); + Provider p = (Provider) providerClass.newInstance(); + providers.add(p); + providersNames.put(p.getName(), p); + initServiceInfo(p); + } catch (ClassNotFoundException ignored) { + } catch (IllegalAccessException ignored) { + } catch (InstantiationException ignored) { + } + } + // Engine.door.renumProviders(); + } + /** + * Returns a copy of the registered providers as an array. + */ + public static synchronized ArrayList getProviders() { + return providers; + } + /** + * Returns the provider with the specified name. + */ + public static synchronized Provider getProvider(String name) { + if (name == null) { + return null; + } + return providersNames.get(name); + } + /** + * Inserts a provider at a specified 1-based position. + */ + public static synchronized int insertProviderAt(Provider provider, int position) { + int size = providers.size(); + if ((position < 1) || (position > size)) { + position = size + 1; + } + providers.add(position - 1, provider); + providersNames.put(provider.getName(), provider); + setNeedRefresh(); + return position; + } + /** + * Removes the provider at the specified 1-based position. + */ + public static synchronized void removeProvider(int providerNumber) { + Provider p = providers.remove(providerNumber - 1); + providersNames.remove(p.getName()); + setNeedRefresh(); + } + /** + * Adds information about provider services into HashMap. + */ + public static synchronized void initServiceInfo(Provider p) { + for (Provider.Service service : p.getServices()) { + String type = service.getType(); + if (cachedSecureRandomService == null && type.equals("SecureRandom")) { + cachedSecureRandomService = service; + } + String key = type + "." + service.getAlgorithm().toUpperCase(Locale.US); + appendServiceLocked(key, service); + /* + for (String alias : Engine.door.getAliases(service)) { + key = type + "." + alias.toUpperCase(Locale.US); + appendServiceLocked(key, service); + } + */ + } + } + /** + * Add or append the service to the key. + */ + private static void appendServiceLocked(String key, Provider.Service service) { + ArrayList serviceList = services.get(key); + if (serviceList == null) { + serviceList = new ArrayList(1); + services.put(key, serviceList); + } + serviceList.add(service); + } + /** + * Returns true if services does not contain any provider information. + */ + public static synchronized boolean isEmpty() { + return services.isEmpty(); + } + /** + * Looks up the requested service by type and algorithm. The + * service key should be provided in the same format used when + * registering a service with a provider, for example, + * "KeyFactory.RSA". + * + * Callers can cache the returned service information but such + * caches should be validated against the result of + * Service.getCacheVersion() before use. + */ + public static synchronized ArrayList getServices(String key) { + return services.get(key); + } + /** + * Returns the default SecureRandom service description. + */ + public static synchronized Provider.Service getSecureRandomService() { + getCacheVersion(); // used for side effect of updating cache if needed + return cachedSecureRandomService; + } + /** + * In addition to being used here when the list of providers + * changes, this method is also used by the Provider + * implementation to indicate that a provides list of services has + * changed. + */ + public static synchronized void setNeedRefresh() { + needRefresh = true; + } + /** + * Returns the current cache version. This has the possible side + * effect of updating the cache if needed. + */ + public static synchronized int getCacheVersion() { + if (needRefresh) { + cacheVersion++; + synchronized (services) { + services.clear(); + } + cachedSecureRandomService = null; + for (Provider p : providers) { + initServiceInfo(p); + } + needRefresh = false; + } + return cacheVersion; + } +} diff --git a/app/src/main/java/org/apache/harmony/x/imageio/internal/nls/Messages.java b/app/src/main/java/org/apache/harmony/x/imageio/internal/nls/Messages.java new file mode 100644 index 000000000..498e1bbe6 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/x/imageio/internal/nls/Messages.java @@ -0,0 +1,124 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * THE FILE HAS BEEN AUTOGENERATED BY MSGTOOL TOOL. + * All changes made to this file manually will be overwritten + * if this tool runs again. Better make changes in the template file. + */ + +package org.apache.harmony.x.imageio.internal.nls; + +import org.apache.harmony.luni.util.MsgHelp; + +/** + * This class retrieves strings from a resource bundle and returns them, + * formatting them with MessageFormat when required. + *

    + * It is used by the system classes to provide national language support, by + * looking up messages in the + * org.apache.harmony.x.imageio.internal.nls.messages + * + * resource bundle. Note that if this file is not available, or an invalid key + * is looked up, or resource bundle support is not available, the key itself + * will be returned as the associated message. This means that the KEY + * should a reasonable human-readable (english) string. + * + */ +public class Messages { + + private static final String sResource = + "org.apache.harmony.x.imageio.internal.nls.messages"; //$NON-NLS-1$ + + /** + * Retrieves a message which has no arguments. + * + * @param msg + * String the key to look up. + * @return String the message for that key in the system message bundle. + */ + static public String getString(String msg) { + return MsgHelp.getString(sResource, msg); + } + + /** + * Retrieves a message which takes 1 argument. + * + * @param msg + * String the key to look up. + * @param arg + * Object the object to insert in the formatted output. + * @return String the message for that key in the system message bundle. + */ + static public String getString(String msg, Object arg) { + return getString(msg, new Object[] { arg }); + } + + /** + * Retrieves a message which takes 1 integer argument. + * + * @param msg + * String the key to look up. + * @param arg + * int the integer to insert in the formatted output. + * @return String the message for that key in the system message bundle. + */ + static public String getString(String msg, int arg) { + return getString(msg, new Object[] { Integer.toString(arg) }); + } + + /** + * Retrieves a message which takes 1 character argument. + * + * @param msg + * String the key to look up. + * @param arg + * char the character to insert in the formatted output. + * @return String the message for that key in the system message bundle. + */ + static public String getString(String msg, char arg) { + return getString(msg, new Object[] { String.valueOf(arg) }); + } + + /** + * Retrieves a message which takes 2 arguments. + * + * @param msg + * String the key to look up. + * @param arg1 + * Object an object to insert in the formatted output. + * @param arg2 + * Object another object to insert in the formatted output. + * @return String the message for that key in the system message bundle. + */ + static public String getString(String msg, Object arg1, Object arg2) { + return getString(msg, new Object[] { arg1, arg2 }); + } + + /** + * Retrieves a message which takes several arguments. + * + * @param msg + * String the key to look up. + * @param args + * Object[] the objects to insert in the formatted output. + * @return String the message for that key in the system message bundle. + */ + static public String getString(String msg, Object[] args) { + return MsgHelp.getString(sResource, msg, args); + } +} diff --git a/app/src/main/java/org/apache/harmony/x/imageio/internal/nls/messages.properties b/app/src/main/java/org/apache/harmony/x/imageio/internal/nls/messages.properties new file mode 100644 index 000000000..8a49dd8fd --- /dev/null +++ b/app/src/main/java/org/apache/harmony/x/imageio/internal/nls/messages.properties @@ -0,0 +1,18 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# messages for EN locale +imageio.1=Wrong bitDepth-numBands composition \ No newline at end of file diff --git a/app/src/main/java/org/apache/harmony/x/imageio/metadata/IIOMetadataUtils.java b/app/src/main/java/org/apache/harmony/x/imageio/metadata/IIOMetadataUtils.java new file mode 100644 index 000000000..caeefdd5c --- /dev/null +++ b/app/src/main/java/org/apache/harmony/x/imageio/metadata/IIOMetadataUtils.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.harmony.x.imageio.metadata; + +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedAction; + +import javax.imageio.metadata.IIOMetadataFormat; +import javax.imageio.metadata.IIOMetadataFormatImpl; + +public class IIOMetadataUtils { + private IIOMetadataUtils() {} + + public static IIOMetadataFormat instantiateMetadataFormat( + String formatName, boolean standardFormatSupported, + String nativeMetadataFormatName, String nativeMetadataFormatClassName, + String [] extraMetadataFormatNames, String [] extraMetadataFormatClassNames + ) { + if (formatName == null) { + throw new IllegalArgumentException("formatName == null!"); + } + if (formatName.equals(IIOMetadataFormatImpl.standardMetadataFormatName)) { + if (standardFormatSupported) { + return IIOMetadataFormatImpl.getStandardFormatInstance(); + } + } + + String className = null; + + if (formatName.equals(nativeMetadataFormatName)) { + className = nativeMetadataFormatClassName; + } else if (extraMetadataFormatNames != null) { + for (int i = 0; i < extraMetadataFormatNames.length; i++) { + if (formatName.equals(extraMetadataFormatNames[i])) { + className = extraMetadataFormatClassNames[i]; + break; + } + } + } + + if (className == null) { + throw new IllegalArgumentException("Unsupported format name"); + } + + // Get the context class loader and try to use it first + ClassLoader contextClassloader = AccessController.doPrivileged( + new PrivilegedAction() { + public ClassLoader run() { + return Thread.currentThread().getContextClassLoader(); + } + }); + + Class cls; + + try { + cls = Class.forName(className, true, contextClassloader); + } catch (ClassNotFoundException e) { + try { + // Use current class loader + cls = Class.forName(className); + } catch (ClassNotFoundException e1) { + throw new IllegalStateException ("Can't obtain format"); + } + } + + try { + //???AWT: + //Method getInstance = cls.getMethod("getInstance"); + //return (IIOMetadataFormat) getInstance.invoke(null); + return null; + } catch (Exception e) { + IllegalStateException e1 = new IllegalStateException("Can't obtain format"); + e1.initCause(e); // Add some details to the message + throw e1; + } + } +} diff --git a/app/src/main/java/org/apache/harmony/x/imageio/plugins/jpeg/IISDecodingImageSource.java b/app/src/main/java/org/apache/harmony/x/imageio/plugins/jpeg/IISDecodingImageSource.java new file mode 100644 index 000000000..051f9065c --- /dev/null +++ b/app/src/main/java/org/apache/harmony/x/imageio/plugins/jpeg/IISDecodingImageSource.java @@ -0,0 +1,115 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem Rafikov + * @version $Revision: 1.2 $ + */ +package org.apache.harmony.x.imageio.plugins.jpeg; + +import javax.imageio.stream.ImageInputStream; + +import org.apache.harmony.awt.gl.image.DecodingImageSource; + +import java.io.InputStream; +import java.io.IOException; + +/** + * This allows usage of the java2d jpegdecoder with ImageInputStream in + * the JPEGImageReader. Temporary, only to make JPEGImageReader#read(..) + * working. + * + */ +public class IISDecodingImageSource extends DecodingImageSource { + + private final InputStream is; + + public IISDecodingImageSource(ImageInputStream iis) { + is = new IISToInputStreamWrapper(iis); + } + + @Override + protected boolean checkConnection() { + return true; + } + + @Override + protected InputStream getInputStream() { + return is; + } + + static class IISToInputStreamWrapper extends InputStream { + + private ImageInputStream input; + + public IISToInputStreamWrapper(ImageInputStream input) { + this.input=input; + } + + @Override + public int read() throws IOException { + return input.read(); + } + + @Override + public int read(byte[] b) throws IOException { + return input.read(b); + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + return input.read(b, off, len); + } + + @Override + public long skip(long n) throws IOException { + return input.skipBytes(n); + } + + @Override + public boolean markSupported() { + return true; // This is orig + + // ???AWT: FIXME + // This is an error in Harmony. Not all input streams + // have mark support and it is not ok to just return true. + // There should be an input.markSupported(). However, if + // this call returns false, nothing works anymore. + + // The backside is that BitmapFactory uses a call to markSupport() + // to find out if it needs to warp the stream in a + // BufferedInputStream to get mark support, and this fails! + + // Currently, the hack is in BitmapFactory, where we always + // wrap the stream in a BufferedInputStream. + } + + @Override + public void mark(int readlimit) { + input.mark(); + } + + @Override + public void reset() throws IOException { + input.reset(); + } + + @Override + public void close() throws IOException { + input.close(); + } + } +} diff --git a/app/src/main/java/org/apache/harmony/x/imageio/plugins/jpeg/JPEGConsts.java b/app/src/main/java/org/apache/harmony/x/imageio/plugins/jpeg/JPEGConsts.java new file mode 100644 index 000000000..067a82505 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/x/imageio/plugins/jpeg/JPEGConsts.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.2 $ + */ +package org.apache.harmony.x.imageio.plugins.jpeg; + +public class JPEGConsts { + + private JPEGConsts() {} + + public static final int SOI = 0xD8; + + //-- IJG (Independed JPEG Group) color spaces + public static final int JCS_UNKNOW = 0; + public static final int JCS_GRAYSCALE = 1; + public static final int JCS_RGB = 2; + public static final int JCS_YCbCr = 3; + public static final int JCS_CMYK = 4; + public static final int JCS_YCC = 5; + public static final int JCS_RGBA = 6; + public static final int JCS_YCbCrA = 7; + public static final int JCS_YCCA = 10; + public static final int JCS_YCCK = 11; + + public static int[][] BAND_OFFSETS = {{}, {0}, {0, 1}, {0, 1, 2}, {0, 1, 2, 3}}; + + public static final float DEFAULT_JPEG_COMPRESSION_QUALITY = 0.75f; +} diff --git a/app/src/main/java/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageReader.java b/app/src/main/java/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageReader.java new file mode 100644 index 000000000..110ed23ac --- /dev/null +++ b/app/src/main/java/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageReader.java @@ -0,0 +1,126 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.4 $ + */ +package org.apache.harmony.x.imageio.plugins.jpeg; + + +import javax.imageio.ImageReader; +import javax.imageio.ImageReadParam; +import javax.imageio.ImageTypeSpecifier; +import javax.imageio.plugins.jpeg.JPEGImageReadParam; +import javax.imageio.stream.ImageInputStream; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.spi.ImageReaderSpi; + +import org.apache.harmony.awt.gl.image.DecodingImageSource; +import org.apache.harmony.awt.gl.image.OffscreenImage; + +import java.io.IOException; +import java.util.Iterator; +import java.awt.image.BufferedImage; + +/** + * This implementation uses org.apache.harmony.awt.gl.image.JpegDecoder to read + * an image. The only implemented method is read(..); + * + * TODO: Implements generic decoder to be used by javad2 and imageio + * + * @see org.apache.harmony.awt.gl.image.JpegDecoder + * @see org.apache.harmony.x.imageio.plugins.jpeg.IISDecodingImageSource + */ +public class JPEGImageReader extends ImageReader { + + ImageInputStream iis; + + public JPEGImageReader(ImageReaderSpi imageReaderSpi) { + super(imageReaderSpi); + } + + @Override + public int getHeight(int i) throws IOException { + //-- TODO imlement + throw new UnsupportedOperationException("not implemented yet"); + } + + @Override + public int getWidth(int i) throws IOException { + //-- TODO imlement + throw new UnsupportedOperationException("not implemented yet"); + } + + @Override + public int getNumImages(boolean b) throws IOException { + //-- TODO imlement + throw new UnsupportedOperationException("not implemented yet"); + } + + @Override + public Iterator getImageTypes(int i) throws IOException { + //-- TODO imlement + throw new UnsupportedOperationException("not implemented yet"); + } + + @Override + public IIOMetadata getStreamMetadata() throws IOException { + //-- TODO imlement + throw new UnsupportedOperationException("not implemented yet"); + } + + @Override + public IIOMetadata getImageMetadata(int i) throws IOException { + //-- TODO imlement + throw new UnsupportedOperationException("not implemented yet"); + } + + @Override + public BufferedImage read(int i, ImageReadParam imageReadParam) throws IOException { + if (iis == null) { + throw new IllegalArgumentException("input stream == null"); + } + + DecodingImageSource source = new IISDecodingImageSource(iis); + OffscreenImage image = new OffscreenImage(source); + source.addConsumer(image); + source.load(); + // The interrupted flag should be cleared because ImageDecoder interrupts + // current thread while decoding. The same technique is used in + // ImageLoader#run(). Another solution can be to create + // a separate decoding thread. However, decoder keeps its own pool + // of threads so creating a new thread will be just a waste of resources. + Thread.interrupted(); + return image.getBufferedImage(); + } + + @Override + public BufferedImage read(int i) throws IOException { + return read(i, null); + } + + @Override + public void setInput(Object input, boolean seekForwardOnly, boolean ignoreMetadata) { + super.setInput(input, seekForwardOnly, ignoreMetadata); + iis = (ImageInputStream) input; + } + + @Override + public ImageReadParam getDefaultReadParam() { + return new JPEGImageReadParam(); + } +} diff --git a/app/src/main/java/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageReaderSpi.java b/app/src/main/java/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageReaderSpi.java new file mode 100644 index 000000000..c719ce77a --- /dev/null +++ b/app/src/main/java/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageReaderSpi.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.3 $ + */ +package org.apache.harmony.x.imageio.plugins.jpeg; + +import java.io.IOException; +import java.util.Locale; +import javax.imageio.ImageReader; +import javax.imageio.spi.ImageReaderSpi; +import javax.imageio.spi.ServiceRegistry; +import javax.imageio.stream.ImageInputStream; + +public class JPEGImageReaderSpi extends ImageReaderSpi { + + public JPEGImageReaderSpi() { + super(JPEGSpiConsts.vendorName, JPEGSpiConsts.version, + JPEGSpiConsts.names, JPEGSpiConsts.suffixes, + JPEGSpiConsts.MIMETypes, JPEGSpiConsts.readerClassName, + STANDARD_INPUT_TYPE, JPEGSpiConsts.writerSpiNames, + JPEGSpiConsts.supportsStandardStreamMetadataFormat, + JPEGSpiConsts.nativeStreamMetadataFormatName, + JPEGSpiConsts.nativeStreamMetadataFormatClassName, + JPEGSpiConsts.extraStreamMetadataFormatNames, + JPEGSpiConsts.extraStreamMetadataFormatClassNames, + JPEGSpiConsts.supportsStandardImageMetadataFormat, + JPEGSpiConsts.nativeImageMetadataFormatName, + JPEGSpiConsts.nativeImageMetadataFormatClassName, + JPEGSpiConsts.extraImageMetadataFormatNames, + JPEGSpiConsts.extraImageMetadataFormatClassNames); + } + + + @Override + public boolean canDecodeInput(Object source) throws IOException { + ImageInputStream markable = (ImageInputStream) source; + try { + markable.mark(); + + byte[] signature = new byte[3]; + markable.seek(0); + markable.read(signature, 0, 3); + markable.reset(); + + if ((signature[0] & 0xFF) == 0xFF && + (signature[1] & 0xFF) == JPEGConsts.SOI && + (signature[2] & 0xFF) == 0xFF) { // JPEG + return true; + } + } catch (IOException e) { + e.printStackTrace(); + } + return false; + } + + @Override + public ImageReader createReaderInstance(Object extension) throws IOException { + return new JPEGImageReader(this); + } + + @Override + public String getDescription(Locale locale) { + return "DRL JPEG decoder"; + } + + @Override + public void onRegistration(ServiceRegistry registry, Class category) { + // super.onRegistration(registry, category); + } +} diff --git a/app/src/main/java/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageWriter.java b/app/src/main/java/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageWriter.java new file mode 100644 index 000000000..ae3e87639 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageWriter.java @@ -0,0 +1,402 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.3 $ + */ +package org.apache.harmony.x.imageio.plugins.jpeg; + +import com.android.internal.awt.ImageOutputStreamWrapper; + +import javax.imageio.ImageWriter; +import javax.imageio.IIOImage; +import javax.imageio.ImageTypeSpecifier; +import javax.imageio.ImageWriteParam; +import javax.imageio.plugins.jpeg.JPEGImageWriteParam; +import javax.imageio.stream.ImageOutputStream; +import javax.imageio.spi.ImageWriterSpi; +import javax.imageio.metadata.IIOMetadata; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Bitmap.CompressFormat; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.awt.image.*; +import java.awt.*; +import java.awt.color.ColorSpace; + +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.3 $ + */ +public class JPEGImageWriter extends ImageWriter { + + // /* ???AWT: Debugging + private static final boolean DEBUG = false; + private static Bitmap bm; + public static Bitmap getBitmap() { + return bm; + } + private static BufferedImage bufImg; + public static BufferedImage getBufImage() { + return bufImg; + } + static private RenderedImage renImg; + static public RenderedImage getRenImage() { + return renImg; + } + // */ + + private long cinfo; + private RenderedImage image; + private Raster sourceRaster; + private WritableRaster scanRaster; + private int srcXOff = 0; + private int srcYOff = 0; + private int srcWidth; + private int srcHeight; + + //-- y step for image subsampling + private int deltaY = 1; + //-- x step for image subsampling + private int deltaX = 1; + + private ImageOutputStream ios; + + public JPEGImageWriter(ImageWriterSpi imageWriterSpi) { + super(imageWriterSpi); + //???AWT: cinfo = initCompressionObj(); + cinfo = System.currentTimeMillis(); + } + + static { + //???AWT + /* + System.loadLibrary("jpegencoder"); + initWriterIds(ImageOutputStream.class); + */ + } + + @Override + public void write(IIOMetadata iioMetadata, IIOImage iioImage, ImageWriteParam param) + throws IOException { + + if (ios == null) { + throw new IllegalArgumentException("ios == null"); + } + if (iioImage == null) { + throw new IllegalArgumentException("Image equals null"); + } + + RenderedImage img = null; + if (!iioImage.hasRaster()) { + img = iioImage.getRenderedImage(); + if (img instanceof BufferedImage) { + sourceRaster = ((BufferedImage) img).getRaster(); + } else { + sourceRaster = img.getData(); + } + } else { + sourceRaster = iioImage.getRaster(); + } + + // AWT???: Debugging + if (DEBUG) { + if( img==null ) { + System.out.println("****J: Image is NULL"); + } else { + renImg = img; + bufImg = (BufferedImage)img; + } + } + + int numBands = sourceRaster.getNumBands(); + int sourceIJGCs = img == null ? JPEGConsts.JCS_UNKNOW : getSourceCSType(img); + + srcWidth = sourceRaster.getWidth(); + srcHeight = sourceRaster.getHeight(); + + int destWidth = srcWidth; + int destHeight = srcHeight; + + boolean progressive = false; + + if (param != null) { + Rectangle reg = param.getSourceRegion(); + if (reg != null) { + srcXOff = reg.x; + srcYOff = reg.y; + + srcWidth = reg.width + srcXOff > srcWidth + ? srcWidth - srcXOff + : reg.width; + srcHeight = reg.height + srcYOff > srcHeight + ? srcHeight - srcYOff + : reg.height; + } + + //-- TODO uncomment when JPEGImageWriteParam be implemented + //-- Only default progressive mode yet + // progressive = param.getProgressiveMode() == ImageWriteParam.MODE_DEFAULT; + + //-- def is 1 + deltaX = param.getSourceXSubsampling(); + deltaY = param.getSourceYSubsampling(); + + //-- def is 0 + int offsetX = param.getSubsamplingXOffset(); + int offsetY = param.getSubsamplingYOffset(); + + srcXOff += offsetX; + srcYOff += offsetY; + srcWidth -= offsetX; + srcHeight -= offsetY; + + destWidth = (srcWidth + deltaX - 1) / deltaX; + destHeight = (srcHeight + deltaY - 1) / deltaY; + } + + //-- default DQTs (see JPEGQTable java doc and JPEG spec K1 & K2 tables) + //-- at http://www.w3.org/Graphics/JPEG/itu-t81.pdf + //-- Only figuring out how to set DQT in IJG library for future metadata + //-- support. IJG def tables are the same. + //JPEGQTable[] dqt = new JPEGQTable[2]; +// int[][] dqt = null; +// int[][] dqt = new int[2][]; +// dqt[0] = JPEGQTable.K1Div2Luminance.getTable(); +// dqt[1] = JPEGQTable.K2Div2Chrominance.getTable(); + + //???AWT: I think we don't need this amymore + /* + //-- using default color space + //-- TODO: Take destination cs from param or use default if there is no cs + int destIJGCs = img == null ? JPEGConsts.JCS_UNKNOW : getDestinationCSType(img); + + DataBufferByte dbuffer = new DataBufferByte(numBands * srcWidth); + + scanRaster = Raster.createInterleavedRaster(dbuffer, srcWidth, 1, + numBands * srcWidth, numBands, JPEGConsts.BAND_OFFSETS[numBands], null); + + encode(dbuffer.getData(), srcWidth, destWidth, destHeight, deltaX, + sourceIJGCs, destIJGCs, numBands, progressive, + null, cinfo); + */ + + SampleModel model = sourceRaster.getSampleModel(); + + if (model instanceof SinglePixelPackedSampleModel) { + DataBufferInt ibuf = (DataBufferInt)sourceRaster.getDataBuffer(); + int[] pixels = ibuf.getData(); + + // Create a bitmap with the pixel + bm = Bitmap.createBitmap(pixels, srcWidth, srcHeight, Bitmap.Config.ARGB_8888); + + // Use Bitmap.compress() to write the image + ImageOutputStreamWrapper iosw = new ImageOutputStreamWrapper(ios); + bm.compress(CompressFormat.JPEG, 100, iosw); + } else { + // ???AWT: Add support for other color models + throw new RuntimeException("Color model not supported yet"); + } + + } + + @Override + public void dispose() { + super.dispose(); + if (cinfo != 0) { + //???AWT: dispose(cinfo); + cinfo = 0; + ios = null; + } + } + + + public IIOMetadata getDefaultStreamMetadata(ImageWriteParam imageWriteParam) { + throw new UnsupportedOperationException("not supported yet"); + } + + public IIOMetadata getDefaultImageMetadata(ImageTypeSpecifier imageTypeSpecifier, ImageWriteParam imageWriteParam) { + throw new UnsupportedOperationException("not supported yet"); + } + + @Override + public IIOMetadata convertStreamMetadata(IIOMetadata iioMetadata, ImageWriteParam imageWriteParam) { + throw new UnsupportedOperationException("not supported yet"); + } + + @Override + public IIOMetadata convertImageMetadata(IIOMetadata iioMetadata, ImageTypeSpecifier imageTypeSpecifier, ImageWriteParam imageWriteParam) { + throw new UnsupportedOperationException("not supported yet"); + } + + @Override + public void setOutput(Object output) { + super.setOutput(output); + ios = (ImageOutputStream) output; + //???AWT: setIOS(ios, cinfo); + sourceRaster = null; + scanRaster = null; + srcXOff = 0; + srcYOff = 0; + srcWidth = 0; + srcHeight = 0; + deltaY = 1; + } + + /** + * Frees resources + * @param structPointer + */ + //???AWT: private native void dispose(long structPointer); + + /** + * Inits methods Ids for native to java callbacks + * @param iosClass + */ + //???AWT: private native static void initWriterIds(Class iosClass); + + /** + * Inits compression objects + * @return pointer to the native structure + */ + //???AWT: private native long initCompressionObj(); + + /** + * Sets image output stream in IJG layer + * @param stream + */ + //???AWT: private native void setIOS(ImageOutputStream stream, long structPointer); + + /** + * Runs encoding process. + * + * @param data image data buffer to encode + * @param srcWidth - source width + * @param width - destination width + * @param height destination height + * @param deltaX - x subsampling step + * @param inColorSpace - original color space + * @param outColorSpace - destination color space + * @param numBands - number of bands + * @param cinfo - native handler + * @return + */ + //???AWT: + /* + private native boolean encode(byte[] data, int srcWidth, + int width, int height, int deltaX, + int inColorSpace, int outColorSpace, + int numBands, boolean progressive, + int[][] dqt, + long cinfo); + */ + + /** + * Callback for getting a next scanline + * @param scanline scan line number + */ + @SuppressWarnings("unused") + private void getScanLine(int scanline) { + //-- TODO: processImageProgress in ImageWriter + Raster child = sourceRaster.createChild(srcXOff, + srcYOff + scanline * deltaY, srcWidth, 1, 0, 0, null); + + scanRaster.setRect(child); + } + + /** + * Maps color space types to IJG color spaces + * @param image + * @return + */ + private int getSourceCSType(RenderedImage image) { + int type = JPEGConsts.JCS_UNKNOW; + ColorModel cm = image.getColorModel(); + + if (null == cm) { + return type; + } + + if (cm instanceof IndexColorModel) { + throw new UnsupportedOperationException("IndexColorModel is not supported yet"); + } + + boolean hasAlpha = cm.hasAlpha(); + ColorSpace cs = cm.getColorSpace(); + switch(cs.getType()) { + case ColorSpace.TYPE_GRAY: + type = JPEGConsts.JCS_GRAYSCALE; + break; + case ColorSpace.TYPE_RGB: + type = hasAlpha ? JPEGConsts.JCS_RGBA : JPEGConsts.JCS_RGB; + break; + case ColorSpace.TYPE_YCbCr: + type = hasAlpha ? JPEGConsts.JCS_YCbCrA : JPEGConsts.JCS_YCbCr; + break; + case ColorSpace.TYPE_3CLR: + type = hasAlpha ? JPEGConsts.JCS_YCCA : JPEGConsts.JCS_YCC; + break; + case ColorSpace.TYPE_CMYK: + type = JPEGConsts.JCS_CMYK; + break; + } + return type; + } + + /** + * Returns destination color space. + * (YCbCr[A] for RGB) + * + * @param image + * @return + */ + private int getDestinationCSType(RenderedImage image) { + int type = JPEGConsts.JCS_UNKNOW; + ColorModel cm = image.getColorModel(); + if (null != cm) { + boolean hasAlpha = cm.hasAlpha(); + ColorSpace cs = cm.getColorSpace(); + + switch(cs.getType()) { + case ColorSpace.TYPE_GRAY: + type = JPEGConsts.JCS_GRAYSCALE; + break; + case ColorSpace.TYPE_RGB: + type = hasAlpha ? JPEGConsts.JCS_YCbCrA : JPEGConsts.JCS_YCbCr; + break; + case ColorSpace.TYPE_YCbCr: + type = hasAlpha ? JPEGConsts.JCS_YCbCrA : JPEGConsts.JCS_YCbCr; + break; + case ColorSpace.TYPE_3CLR: + type = hasAlpha ? JPEGConsts.JCS_YCCA : JPEGConsts.JCS_YCC; + break; + case ColorSpace.TYPE_CMYK: + type = JPEGConsts.JCS_CMYK; + break; + } + } + return type; + } + + public ImageWriteParam getDefaultWriteParam() { + return new JPEGImageWriteParam(getLocale()); + } +} diff --git a/app/src/main/java/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageWriterSpi.java b/app/src/main/java/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageWriterSpi.java new file mode 100644 index 000000000..b7990e088 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/x/imageio/plugins/jpeg/JPEGImageWriterSpi.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.3 $ + */ +package org.apache.harmony.x.imageio.plugins.jpeg; + +import javax.imageio.spi.ImageWriterSpi; +import javax.imageio.ImageWriter; +import javax.imageio.ImageTypeSpecifier; +import java.io.IOException; +import java.util.Locale; + +public class JPEGImageWriterSpi extends ImageWriterSpi { + + public JPEGImageWriterSpi() { + super(JPEGSpiConsts.vendorName, JPEGSpiConsts.version, + JPEGSpiConsts.names, JPEGSpiConsts.suffixes, JPEGSpiConsts.MIMETypes, + JPEGSpiConsts.writerClassName, STANDARD_OUTPUT_TYPE, + JPEGSpiConsts.readerSpiNames, JPEGSpiConsts.supportsStandardStreamMetadataFormat /*TODO: support st. metadata format*/, + JPEGSpiConsts.nativeStreamMetadataFormatName, JPEGSpiConsts.nativeStreamMetadataFormatClassName, + JPEGSpiConsts.extraStreamMetadataFormatNames, JPEGSpiConsts.extraStreamMetadataFormatClassNames, + JPEGSpiConsts.supportsStandardImageMetadataFormat, JPEGSpiConsts.nativeImageMetadataFormatName, JPEGSpiConsts.nativeImageMetadataFormatClassName, + JPEGSpiConsts.extraImageMetadataFormatNames, JPEGSpiConsts.extraImageMetadataFormatClassNames); + } + + @Override + public boolean canEncodeImage(ImageTypeSpecifier imageTypeSpecifier) { + return true; + } + + @Override + public ImageWriter createWriterInstance(Object o) throws IOException { + return new JPEGImageWriter(this); + } + + @Override + public String getDescription(Locale locale) { + return "DRL JPEG Encoder"; + } +} diff --git a/app/src/main/java/org/apache/harmony/x/imageio/plugins/jpeg/JPEGSpiConsts.java b/app/src/main/java/org/apache/harmony/x/imageio/plugins/jpeg/JPEGSpiConsts.java new file mode 100644 index 000000000..c3b4a506f --- /dev/null +++ b/app/src/main/java/org/apache/harmony/x/imageio/plugins/jpeg/JPEGSpiConsts.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.2 $ + */ +package org.apache.harmony.x.imageio.plugins.jpeg; + +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.2 $ + */ +public class JPEGSpiConsts { + private JPEGSpiConsts() {} + + public static final String vendorName = "Intel Corporation"; + public static final String version = "0.1 beta"; + + static final String readerClassName = "org.apache.harmony.x.imageio.plugins.jpeg.JPEGImageReader"; + static final String writerClassName = "org.apache.harmony.x.imageio.plugins.jpeg.JPEGImageWriter"; + + static final String[] names = {"jpeg", "jpg", "JPEG", "JPG"}; + static final String[] suffixes = {"jpeg", "jpg"}; + static final String[] MIMETypes = {"image/jpeg"}; + + static final String[] writerSpiNames = {"org.apache.harmony.x.imageio.plugins.jpeg.JPEGImageWriterSpi"}; + static final String[] readerSpiNames = {"org.apache.harmony.x.imageio.plugins.jpeg.JPEGImageReaderSpi"}; + + //-- TODO fill this stuff with correct data + static final boolean supportsStandardStreamMetadataFormat = false; + static final String nativeStreamMetadataFormatName = null; + static final String nativeStreamMetadataFormatClassName = null; + static final String[] extraStreamMetadataFormatNames = null; + static final String[] extraStreamMetadataFormatClassNames = null; + static final boolean supportsStandardImageMetadataFormat = false; + static final String nativeImageMetadataFormatName = + "org.apache.harmony.x.imageio.plugins.jpeg.MyFormatMetadata_1.0"; + static final String nativeImageMetadataFormatClassName = + "org.apache.harmony.x.imageio.plugins.jpeg.MyFormatMetadata"; + static final String[] extraImageMetadataFormatNames = null; + static final String[] extraImageMetadataFormatClassNames = null; + +} diff --git a/app/src/main/java/org/apache/harmony/x/imageio/plugins/png/PNGImageReader.java b/app/src/main/java/org/apache/harmony/x/imageio/plugins/png/PNGImageReader.java new file mode 100644 index 000000000..480041c9c --- /dev/null +++ b/app/src/main/java/org/apache/harmony/x/imageio/plugins/png/PNGImageReader.java @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.harmony.x.imageio.plugins.png; + +import org.apache.harmony.awt.gl.image.DecodingImageSource; +import org.apache.harmony.awt.gl.image.OffscreenImage; +import org.apache.harmony.x.imageio.plugins.jpeg.IISDecodingImageSource; + +import javax.imageio.ImageReader; +import javax.imageio.ImageTypeSpecifier; +import javax.imageio.ImageReadParam; +import javax.imageio.plugins.jpeg.JPEGImageReadParam; +import javax.imageio.spi.ImageReaderSpi; +import javax.imageio.stream.ImageInputStream; +import javax.imageio.metadata.IIOMetadata; +import java.io.IOException; +import java.util.Iterator; +import java.awt.image.BufferedImage; + +public class PNGImageReader extends ImageReader { + ImageInputStream iis; + + public PNGImageReader(ImageReaderSpi imageReaderSpi) { + super(imageReaderSpi); + } + + public int getNumImages(boolean allowSearch) throws IOException { + //-- TODO imlement + throw new UnsupportedOperationException("not implemented yet"); + } + + public int getWidth(int imageIndex) throws IOException { + //-- TODO imlement + throw new UnsupportedOperationException("not implemented yet"); + } + + public int getHeight(int imageIndex) throws IOException { + //-- TODO imlement + throw new UnsupportedOperationException("not implemented yet"); + } + + public Iterator getImageTypes(int imageIndex) throws IOException { + //-- TODO imlement + throw new UnsupportedOperationException("not implemented yet"); + } + + @Override + public IIOMetadata getStreamMetadata() throws IOException { + //-- TODO imlement + throw new UnsupportedOperationException("not implemented yet"); + } + + @Override + public IIOMetadata getImageMetadata(int imageIndex) throws IOException { + //-- TODO imlement + throw new UnsupportedOperationException("not implemented yet"); + } + + @Override + public BufferedImage read(int i, ImageReadParam imageReadParam) throws IOException { + if (iis == null) { + throw new IllegalArgumentException("input stream == null"); + } + + DecodingImageSource source = new IISDecodingImageSource(iis); + OffscreenImage image = new OffscreenImage(source); + source.addConsumer(image); + source.load(); + // The interrupted flag should be cleared because ImageDecoder interrupts + // current thread while decoding (due its architecture). + Thread.interrupted(); + return image.getBufferedImage(); + } + + @Override + public BufferedImage read(int i) throws IOException { + return read(i, null); + } + + @Override + public void setInput(Object input, boolean seekForwardOnly, boolean ignoreMetadata) { + super.setInput(input, seekForwardOnly, ignoreMetadata); + iis = (ImageInputStream) input; + } + + @Override + public ImageReadParam getDefaultReadParam() { + return new ImageReadParam(); + } +} diff --git a/app/src/main/java/org/apache/harmony/x/imageio/plugins/png/PNGImageReaderSpi.java b/app/src/main/java/org/apache/harmony/x/imageio/plugins/png/PNGImageReaderSpi.java new file mode 100644 index 000000000..50f8b1078 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/x/imageio/plugins/png/PNGImageReaderSpi.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.harmony.x.imageio.plugins.png; + +import org.apache.harmony.x.imageio.plugins.jpeg.JPEGSpiConsts; + +import javax.imageio.spi.ImageReaderSpi; +import javax.imageio.spi.ServiceRegistry; +import javax.imageio.ImageReader; +import javax.imageio.stream.ImageInputStream; +import java.io.IOException; +import java.util.Locale; + +public class PNGImageReaderSpi extends ImageReaderSpi { + static final String PNG_NAMES[] = new String[] {"png", "PNG"}; + static final String PNG_SUFFIXES[] = new String[] {"png"}; + static final String PNG_MIME_TYPES[] = new String[] {"image/png"}; + static final String PNG_READER_CLASS_NAME = "org.apache.harmony.x.imageio.plugins.png.PNGImageReader"; + static final String PNG_READER_SPI_NAMES[] = {"org.apache.harmony.x.imageio.plugins.png.PNGImageReaderSpi"}; + + public PNGImageReaderSpi() { + super( + JPEGSpiConsts.vendorName, JPEGSpiConsts.version, + PNG_NAMES, PNG_SUFFIXES, + PNG_MIME_TYPES, PNG_READER_CLASS_NAME, + STANDARD_INPUT_TYPE, null, + false, null, + null, null, + null, false, + null, null, + null, null + ); + } + + @Override + public boolean canDecodeInput(Object source) throws IOException { + ImageInputStream markable = (ImageInputStream) source; + markable.mark(); + + byte[] signature = new byte[8]; + markable.seek(0); + + int nBytes = markable.read(signature, 0, 8); + if(nBytes != 8) markable.read(signature, nBytes, 8-nBytes); + markable.reset(); + + // PNG signature: 137 80 78 71 13 10 26 10 + return (signature[0] & 0xFF) == 137 && + (signature[1] & 0xFF) == 80 && + (signature[2] & 0xFF) == 78 && + (signature[3] & 0xFF) == 71 && + (signature[4] & 0xFF) == 13 && + (signature[5] & 0xFF) == 10 && + (signature[6] & 0xFF) == 26 && + (signature[7] & 0xFF) == 10; + } + + @Override + public ImageReader createReaderInstance(Object extension) throws IOException { + return new PNGImageReader(this); + } + + @Override + public String getDescription(Locale locale) { + return "DRL PNG decoder"; + } + + @Override + public void onRegistration(ServiceRegistry registry, Class category) { + super.onRegistration(registry, category); + } +} diff --git a/app/src/main/java/org/apache/harmony/x/imageio/plugins/png/PNGImageWriter.java b/app/src/main/java/org/apache/harmony/x/imageio/plugins/png/PNGImageWriter.java new file mode 100644 index 000000000..e2a8d7de6 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/x/imageio/plugins/png/PNGImageWriter.java @@ -0,0 +1,247 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Viskov Nikolay + * @version $Revision$ + */ +package org.apache.harmony.x.imageio.plugins.png; + +import com.android.internal.awt.ImageOutputStreamWrapper; + +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.DataBufferByte; +import java.awt.image.DataBufferInt; +import java.awt.image.IndexColorModel; +import java.awt.image.Raster; +import java.awt.image.RenderedImage; +import java.awt.image.SampleModel; +import java.awt.image.SinglePixelPackedSampleModel; +import java.awt.image.WritableRaster; +import java.io.IOException; + +import javax.imageio.IIOImage; +import javax.imageio.ImageTypeSpecifier; +import javax.imageio.ImageWriteParam; +import javax.imageio.ImageWriter; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.spi.ImageWriterSpi; +import javax.imageio.stream.ImageOutputStream; + +import org.apache.harmony.x.imageio.internal.nls.Messages; + +import org.apache.harmony.luni.util.NotImplementedException; + +import android.graphics.Bitmap; +import android.graphics.Bitmap.CompressFormat; + +public class PNGImageWriter extends ImageWriter { + + // /* ???AWT: Debugging + private static final boolean DEBUG = false; + private static Bitmap bm; + public static Bitmap getBitmap() { + return bm; + } + // */ + + private static int[][] BAND_OFFSETS = { + {}, { + 0 }, { + 0, 1 }, { + 0, 1, 2 }, { + 0, 1, 2, 3 } }; + + // Each pixel is a grayscale sample. + private static final int PNG_COLOR_TYPE_GRAY = 0; + // Each pixel is an R,G,B triple. + private static final int PNG_COLOR_TYPE_RGB = 2; + // Each pixel is a palette index, a PLTE chunk must appear. + private static final int PNG_COLOR_TYPE_PLTE = 3; + // Each pixel is a grayscale sample, followed by an alpha sample. + private static final int PNG_COLOR_TYPE_GRAY_ALPHA = 4; + // Each pixel is an R,G,B triple, followed by an alpha sample. + private static final int PNG_COLOR_TYPE_RGBA = 6; + + //???AWT: private static native void initIDs(Class iosClass); + + static { + //???AWT + /* + System.loadLibrary("pngencoder"); //$NON-NLS-1$ + initIDs(ImageOutputStream.class); + */ + } + + /* + private native int encode(byte[] input, int bytesInBuffer, int bytePixelSize, Object ios, int imageWidth, + int imageHeight, int bitDepth, int colorType, int[] palette, int i, boolean b); + */ + + protected PNGImageWriter(ImageWriterSpi iwSpi) { + super(iwSpi); + } + + @Override + public IIOMetadata convertStreamMetadata(IIOMetadata arg0, ImageWriteParam arg1) { + throw new NotImplementedException(); + } + + @Override + public IIOMetadata convertImageMetadata(IIOMetadata arg0, ImageTypeSpecifier arg1, ImageWriteParam arg2) { + throw new NotImplementedException(); + } + + @Override + public IIOMetadata getDefaultImageMetadata(ImageTypeSpecifier arg0, ImageWriteParam arg1) { + throw new NotImplementedException(); + } + + @Override + public IIOMetadata getDefaultStreamMetadata(ImageWriteParam arg0) { + throw new NotImplementedException(); + } + + @Override + public void write(IIOMetadata streamMetadata, IIOImage iioImage, ImageWriteParam param) throws IOException { + if (output == null) { + throw new IllegalStateException("Output not been set"); + } + if (iioImage == null) { + throw new IllegalArgumentException("Image equals null"); + } + // AWT???: I think this is not needed anymore + // if (iioImage.hasRaster() && !canWriteRasters()) { + // throw new UnsupportedOperationException("Can't write raster"); + //}// ImageOutputStreamImpl + + Raster sourceRaster; + RenderedImage img = null; + if (!iioImage.hasRaster()) { + img = iioImage.getRenderedImage(); + if (img instanceof BufferedImage) { + sourceRaster = ((BufferedImage) img).getRaster(); + } else { + sourceRaster = img.getData(); + } + } else { + sourceRaster = iioImage.getRaster(); + } + + SampleModel model = sourceRaster.getSampleModel(); + int srcWidth = sourceRaster.getWidth(); + int srcHeight = sourceRaster.getHeight(); + int numBands = model.getNumBands(); + + ColorModel colorModel = img.getColorModel(); + int pixelSize = colorModel.getPixelSize(); + int bytePixelSize = pixelSize / 8; + int bitDepth = pixelSize / numBands; + + // byte per band + int bpb = bitDepth > 8 ? 2 : 1; + + boolean isInterlace = true; + if (param instanceof PNGImageWriterParam) { + isInterlace = ((PNGImageWriterParam) param).getInterlace(); + } + + int colorType = PNG_COLOR_TYPE_GRAY; + int[] palette = null; + + if (colorModel instanceof IndexColorModel) { + if (bitDepth != 1 && bitDepth != 2 && bitDepth != 4 && bitDepth != 8) { +// Wrong bitDepth-numBands composition + throw new IllegalArgumentException(Messages.getString("imageio.1"));//$NON-NLS-1$ + } + if (numBands != 1) { +// Wrong bitDepth-numBands composition + throw new IllegalArgumentException(Messages.getString("imageio.1"));//$NON-NLS-1$ + } + + IndexColorModel icm = (IndexColorModel) colorModel; + palette = new int[icm.getMapSize()]; + icm.getRGBs(palette); + colorType = PNG_COLOR_TYPE_PLTE; + } + else if (numBands == 1) { + if (bitDepth != 1 && bitDepth != 2 && bitDepth != 4 && bitDepth != 8 && bitDepth != 16) { +// Wrong bitDepth-numBands composition + throw new IllegalArgumentException(Messages.getString("imageio.1"));//$NON-NLS-1$ + } + colorType = PNG_COLOR_TYPE_GRAY; + } + else if (numBands == 2) { + if (bitDepth != 8 && bitDepth != 16) { +// Wrong bitDepth-numBands composition + throw new IllegalArgumentException(Messages.getString("imageio.1"));//$NON-NLS-1$ + } + colorType = PNG_COLOR_TYPE_GRAY_ALPHA; + } + else if (numBands == 3) { + if (bitDepth != 8 && bitDepth != 16) { +// Wrong bitDepth-numBands composition + throw new IllegalArgumentException(Messages.getString("imageio.1")); //$NON-NLS-1$ + } + colorType = PNG_COLOR_TYPE_RGB; + } + else if (numBands == 4) { + if (bitDepth != 8 && bitDepth != 16) { + //Wrong bitDepth-numBands composition + throw new IllegalArgumentException(Messages.getString("imageio.1")); //$NON-NLS-1$ + } + colorType = PNG_COLOR_TYPE_RGBA; + } + + /* ???AWT: I think this is not needed anymore + int dbufferLenght = bytePixelSize * imageHeight * imageWidth; + DataBufferByte dbuffer = new DataBufferByte(dbufferLenght); + + WritableRaster scanRaster = Raster.createInterleavedRaster(dbuffer, imageWidth, imageHeight, bpb * numBands + * imageWidth, bpb * numBands, BAND_OFFSETS[numBands], null); + + scanRaster.setRect(((BufferedImage) image).getRaster()// image.getData() + .createChild(0, 0, imageWidth, imageHeight, 0, 0, null)); + */ + + if (DEBUG) { + System.out.println("**** raster:" + sourceRaster); + System.out.println("**** model:" + model); + System.out.println("**** type:" + colorType); + } + + if (model instanceof SinglePixelPackedSampleModel) { + DataBufferInt ibuf = (DataBufferInt)sourceRaster.getDataBuffer(); + int[] pixels = ibuf.getData(); + + // Create a bitmap with the pixel + bm = Bitmap.createBitmap(pixels, srcWidth, srcHeight, Bitmap.Config.ARGB_8888); + + // Use Bitmap.compress() to write the image + ImageOutputStream ios = (ImageOutputStream) getOutput(); + ImageOutputStreamWrapper iosw = new ImageOutputStreamWrapper(ios); + bm.compress(CompressFormat.PNG, 100, iosw); + } else { + // ???AWT: Add support for other color models + throw new RuntimeException("Color model not supported yet"); + } + } + + public ImageWriteParam getDefaultWriteParam() { + return new PNGImageWriterParam(); + } +} diff --git a/app/src/main/java/org/apache/harmony/x/imageio/plugins/png/PNGImageWriterParam.java b/app/src/main/java/org/apache/harmony/x/imageio/plugins/png/PNGImageWriterParam.java new file mode 100644 index 000000000..bf3a0003a --- /dev/null +++ b/app/src/main/java/org/apache/harmony/x/imageio/plugins/png/PNGImageWriterParam.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Viskov Nikolay + * @version $Revision$ + */ +package org.apache.harmony.x.imageio.plugins.png; + +import javax.imageio.ImageWriteParam; + +public class PNGImageWriterParam extends ImageWriteParam { + + private boolean isInterlace = true; + + public PNGImageWriterParam() { + super(); + } + + public boolean getInterlace() { + return isInterlace; + } + + public void setInterlace(boolean b) { + isInterlace = b; + } + +} diff --git a/app/src/main/java/org/apache/harmony/x/imageio/plugins/png/PNGImageWriterSpi.java b/app/src/main/java/org/apache/harmony/x/imageio/plugins/png/PNGImageWriterSpi.java new file mode 100644 index 000000000..6eed14dfc --- /dev/null +++ b/app/src/main/java/org/apache/harmony/x/imageio/plugins/png/PNGImageWriterSpi.java @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Viskov Nikolay + * @version $Revision$ + */ +package org.apache.harmony.x.imageio.plugins.png; + +import java.awt.image.ColorModel; +import java.awt.image.DataBufferByte; +import java.awt.image.IndexColorModel; +import java.io.IOException; +import java.util.Locale; + +import javax.imageio.ImageTypeSpecifier; +import javax.imageio.ImageWriter; +import javax.imageio.spi.ImageWriterSpi; + +public class PNGImageWriterSpi extends ImageWriterSpi { + + public PNGImageWriterSpi() { + super("Intel Corporation",// vendorName + "1.0",// version + new String[] { + "png", "PNG" },// names + new String[] { + "png", "PNG" },// suffixes + new String[] { + "image/png" },// MIMETypes + "org.apache.harmony.x.imageio.plugins.png.PNGImageWriter",// writerClassName + STANDARD_OUTPUT_TYPE,// outputTypes + new String[] { + "org.apache.harmony.x.imageio.plugins.png.PNGImageWriterSpi" },// readerSpiNames + false,// supportsStandardStreamMetadataFormat + null,// nativeStreamMetadataFormatName + null,// nativeStreamMetadataFormatClassName + null,// extraStreamMetadataFormatNames + null,// extraStreamMetadataFormatClassNames + false,// supportsStandardImageMetadataFormat + null,// nativeImageMetadataFormatName + null,// nativeImageMetadataFormatClassName + null,// extraImageMetadataFormatNames + null// extraImageMetadataFormatClassNames + ); + } + + @Override + public boolean canEncodeImage(ImageTypeSpecifier type) { + boolean canEncode = true; + + int numBands = type.getSampleModel().getNumBands(); + + ColorModel colorModel = type.getColorModel(); + + int bitDepth = colorModel.getPixelSize() / numBands; + + if (colorModel instanceof IndexColorModel) { + if (bitDepth != 1 && bitDepth != 2 && bitDepth != 4 && bitDepth != 8) { + canEncode = false; + } + if (numBands != 1) { + canEncode = false; + } + } + else if (numBands == 1) { + if (bitDepth != 1 && bitDepth != 2 && bitDepth != 4 && bitDepth != 8 && bitDepth != 16) { + canEncode = false; + } + } + else if (numBands == 2) { + if (bitDepth != 8 && bitDepth != 16) { + canEncode = false; + } + } + else if (numBands == 3) { + if (bitDepth != 8 && bitDepth != 16) { + canEncode = false; + } + } + else if (numBands == 4) { + if (bitDepth != 8 && bitDepth != 16) { + canEncode = false; + } + } + + return canEncode; + } + + @Override + public ImageWriter createWriterInstance(Object arg0) throws IOException { + return new PNGImageWriter(this); + } + + @Override + public String getDescription(Locale arg0) { + return "DRL PNG encoder"; + } + +} diff --git a/app/src/main/java/org/apache/harmony/x/imageio/spi/FileIISSpi.java b/app/src/main/java/org/apache/harmony/x/imageio/spi/FileIISSpi.java new file mode 100644 index 000000000..d4fdd764f --- /dev/null +++ b/app/src/main/java/org/apache/harmony/x/imageio/spi/FileIISSpi.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.2 $ + */ +package org.apache.harmony.x.imageio.spi; + +import javax.imageio.spi.ImageInputStreamSpi; +import javax.imageio.stream.ImageInputStream; +import javax.imageio.stream.FileImageOutputStream; +import javax.imageio.stream.FileImageInputStream; +import java.io.File; +import java.io.IOException; +import java.util.Locale; + +public class FileIISSpi extends ImageInputStreamSpi { + private static final String vendor = "Apache"; + + private static final String ver = "0.1"; + + public FileIISSpi() { + super(vendor, ver, File.class); + } + + @Override + public ImageInputStream createInputStreamInstance(Object input, boolean useCache, + File cacheDir) throws IOException { + if (File.class.isInstance(input)) { + return new FileImageInputStream((File) input); + } + throw new IllegalArgumentException("input is not an instance of java.io.File"); + } + + @Override + public String getDescription(Locale locale) { + return "File IIS Spi"; + } +} diff --git a/app/src/main/java/org/apache/harmony/x/imageio/spi/FileIOSSpi.java b/app/src/main/java/org/apache/harmony/x/imageio/spi/FileIOSSpi.java new file mode 100644 index 000000000..acda6a1bf --- /dev/null +++ b/app/src/main/java/org/apache/harmony/x/imageio/spi/FileIOSSpi.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.2 $ + */ +package org.apache.harmony.x.imageio.spi; + +import javax.imageio.spi.ImageOutputStreamSpi; +import javax.imageio.stream.ImageOutputStream; +import javax.imageio.stream.FileImageOutputStream; +import java.io.File; +import java.io.IOException; +import java.util.Locale; + +public class FileIOSSpi extends ImageOutputStreamSpi { + private static final String vendor = "Apache"; + + private static final String ver = "0.1"; + + public FileIOSSpi() { + super(vendor, ver, File.class); + } + + @Override + public ImageOutputStream createOutputStreamInstance(Object output, boolean useCache, + File cacheDir) throws IOException { + if (output instanceof File) { + return new FileImageOutputStream((File) output); + } + throw new IllegalArgumentException("output is not instance of File"); + } + + @Override + public String getDescription(Locale locale) { + return "File IOS Spi"; + } +} diff --git a/app/src/main/java/org/apache/harmony/x/imageio/spi/InputStreamIISSpi.java b/app/src/main/java/org/apache/harmony/x/imageio/spi/InputStreamIISSpi.java new file mode 100644 index 000000000..ed2fef076 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/x/imageio/spi/InputStreamIISSpi.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.harmony.x.imageio.spi; + +import javax.imageio.spi.ImageInputStreamSpi; +import javax.imageio.stream.*; +import java.io.OutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Locale; + +public class InputStreamIISSpi extends ImageInputStreamSpi { + private static final String vendor = "Apache"; + + private static final String ver = "0.1"; + + public InputStreamIISSpi() { + super(vendor, ver, InputStream.class); + } + + @Override + public String getDescription(Locale locale) { + return "Output Stream IOS Spi"; + } + + @Override + public boolean canUseCacheFile() { + return true; + } + + @Override + public ImageInputStream createInputStreamInstance(Object input, boolean useCache, File cacheDir) throws IOException { + if (input instanceof InputStream) { + if (useCache) { + return new FileCacheImageInputStream((InputStream) input, cacheDir); + } else { + return new MemoryCacheImageInputStream((InputStream) input); + } + } + throw new IllegalArgumentException("Output is not an instance of InputStream"); + } +} diff --git a/app/src/main/java/org/apache/harmony/x/imageio/spi/OutputStreamIOSSpi.java b/app/src/main/java/org/apache/harmony/x/imageio/spi/OutputStreamIOSSpi.java new file mode 100644 index 000000000..dd1e88dd4 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/x/imageio/spi/OutputStreamIOSSpi.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.harmony.x.imageio.spi; + +import javax.imageio.spi.ImageOutputStreamSpi; +import javax.imageio.stream.ImageOutputStream; +import javax.imageio.stream.FileCacheImageOutputStream; +import javax.imageio.stream.MemoryCacheImageOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Locale; + +public class OutputStreamIOSSpi extends ImageOutputStreamSpi { + private static final String vendor = "Apache"; + + private static final String ver = "0.1"; + + public OutputStreamIOSSpi() { + super(vendor, ver, OutputStream.class); + } + + @Override + public ImageOutputStream createOutputStreamInstance(Object output, boolean useCache, File cacheDir) throws IOException { + if (output instanceof OutputStream) { + if (useCache) { + return new FileCacheImageOutputStream((OutputStream) output, cacheDir); + } else { + return new MemoryCacheImageOutputStream((OutputStream) output); + } + } + throw new IllegalArgumentException("Output is not an instance of OutputStream"); + } + + @Override + public String getDescription(Locale locale) { + return "Output Stream IOS Spi"; + } + + @Override + public boolean canUseCacheFile() { + return true; + } +} diff --git a/app/src/main/java/org/apache/harmony/x/imageio/spi/RAFIISSpi.java b/app/src/main/java/org/apache/harmony/x/imageio/spi/RAFIISSpi.java new file mode 100644 index 000000000..f97eb87e2 --- /dev/null +++ b/app/src/main/java/org/apache/harmony/x/imageio/spi/RAFIISSpi.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.2 $ + */ +package org.apache.harmony.x.imageio.spi; + +import javax.imageio.spi.ImageInputStreamSpi; +import javax.imageio.stream.ImageInputStream; +import javax.imageio.stream.FileImageInputStream; +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.Locale; + +public class RAFIISSpi extends ImageInputStreamSpi { + private static final String vendor = "Apache"; + + private static final String ver = "0.1"; + + public RAFIISSpi() { + super(vendor, ver, RandomAccessFile.class); + } + + @Override + public ImageInputStream createInputStreamInstance(Object input, boolean useCache, + File cacheDir) throws IOException { + if (RandomAccessFile.class.isInstance(input)) { + return new FileImageInputStream((RandomAccessFile) input); + } + throw new IllegalArgumentException( + "input is not an instance of java.io.RandomAccessFile"); + } + + @Override + public String getDescription(Locale locale) { + return "RandomAccessFile IIS Spi"; + } +} diff --git a/app/src/main/java/org/apache/harmony/x/imageio/spi/RAFIOSSpi.java b/app/src/main/java/org/apache/harmony/x/imageio/spi/RAFIOSSpi.java new file mode 100644 index 000000000..a9d36492a --- /dev/null +++ b/app/src/main/java/org/apache/harmony/x/imageio/spi/RAFIOSSpi.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Rustem V. Rafikov + * @version $Revision: 1.2 $ + */ +package org.apache.harmony.x.imageio.spi; + +import javax.imageio.spi.ImageOutputStreamSpi; +import javax.imageio.stream.ImageOutputStream; +import javax.imageio.stream.FileImageOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.Locale; + +public class RAFIOSSpi extends ImageOutputStreamSpi { + private static final String vendor = "Apache"; + + private static final String ver = "0.1"; + + public RAFIOSSpi() { + super(vendor, ver, RandomAccessFile.class); + } + + @Override + public ImageOutputStream createOutputStreamInstance(Object output, boolean useCache, + File cacheDir) throws IOException { + if (output instanceof RandomAccessFile) { + return new FileImageOutputStream((RandomAccessFile) output); + } + throw new IllegalArgumentException("output is not instance of java.io.RandomAccessFile"); + } + + @Override + public String getDescription(Locale locale) { + return "RandomAccessFile IOS Spi"; + } +} diff --git a/app/src/main/java/org/apache/harmony/x/imageio/stream/RandomAccessMemoryCache.java b/app/src/main/java/org/apache/harmony/x/imageio/stream/RandomAccessMemoryCache.java new file mode 100644 index 000000000..b4afb182a --- /dev/null +++ b/app/src/main/java/org/apache/harmony/x/imageio/stream/RandomAccessMemoryCache.java @@ -0,0 +1,226 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.harmony.x.imageio.stream; + +import java.util.ArrayList; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +public final class RandomAccessMemoryCache { + private static final int BLOCK_SHIFT = 9; + private static final int BLOCK_SIZE = 1 << BLOCK_SHIFT; + private static final int BLOCK_MASK = BLOCK_SIZE - 1; + + private long length; + + private int firstUndisposed = 0; + + private ArrayList blocks = new ArrayList(); + + public RandomAccessMemoryCache() { + } + + public long length() { + return length; + } + + public void close() { + blocks.clear(); + length = 0; + } + + private void grow(long pos) { + int blocksNeeded = (int)(pos >> BLOCK_SHIFT) - blocks.size() + 1; + for (int i=0; i < blocksNeeded; i++) { + blocks.add(new byte[BLOCK_SIZE]); + } + + length = pos + 1; + } + + public void putData(int oneByte, long pos) { + if (pos >= length) { + grow(pos); + } + + byte[] block = blocks.get((int)(pos >> BLOCK_SHIFT)); + block[(int)(pos & BLOCK_MASK)] = (byte) oneByte; + } + + public void putData(byte[] buffer, int offset, int count, long pos) { + if (count > buffer.length - offset || count < 0 || offset < 0) { + throw new IndexOutOfBoundsException(); + } + if (count == 0){ + return; + } + + long lastPos = pos + count - 1; + if (lastPos >= length) { + grow(lastPos); + } + + while (count > 0) { + byte[] block = blocks.get((int)(pos >> BLOCK_SHIFT)); + int blockOffset = (int)(pos & BLOCK_MASK); + int toCopy = Math.min(BLOCK_SIZE - blockOffset, count); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(buffer, offset, block, blockOffset, toCopy); + pos += toCopy; + count -= toCopy; + offset += toCopy; + } + } + + public int getData(long pos) { + if (pos >= length) { + return -1; + } + + byte[] block = blocks.get((int)(pos >> BLOCK_SHIFT)); + return block[(int)(pos & BLOCK_MASK)] & 0xFF; + } + + public int getData(byte[] buffer, int offset, int count, long pos) { + if (count > buffer.length - offset || count < 0 || offset < 0) { + throw new IndexOutOfBoundsException(); + } + if (count == 0) { + return 0; + } + if (pos >= length) { + return -1; + } + + if (count + pos > length) { + count = (int) (length - pos); + } + + byte[] block = blocks.get((int)(pos >> BLOCK_SHIFT)); + int nbytes = Math.min(count, BLOCK_SIZE - (int)(pos & BLOCK_MASK)); + net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(block, (int)(pos & BLOCK_MASK), buffer, offset, nbytes); + + return nbytes; + } + /* + public void seek(long pos) throws IOException { + if (pos < 0) { + throw new IOException("seek position is negative"); + } + this.pos = pos; + } + + public void readFully(byte[] buffer) throws IOException { + readFully(buffer, 0, buffer.length); + } + + public void readFully(byte[] buffer, int offset, int count) throws IOException { + if (0 <= offset && offset <= buffer.length && 0 <= count && count <= buffer.length - offset) { + while (count > 0) { + int result = read(buffer, offset, count); + if (result >= 0) { + offset += result; + count -= result; + } else { + throw new EOFException(); + } + } + } else { + throw new IndexOutOfBoundsException(); + } + } + + public long getFilePointer() { + return pos; + } +*/ + + public void freeBefore(long pos) { + int blockIdx = (int)(pos >> BLOCK_SHIFT); + if (blockIdx <= firstUndisposed) { // Nothing to do + return; + } + + for (int i = firstUndisposed; i < blockIdx; i++) { + blocks.set(i, null); + } + + firstUndisposed = blockIdx; + } + + public int appendData(InputStream is, int count) throws IOException { + if (count <= 0) { + return 0; + } + + long startPos = length; + long lastPos = length + count - 1; + grow(lastPos); // Changes length + + int blockIdx = (int)(startPos >> BLOCK_SHIFT); + int offset = (int) (startPos & BLOCK_MASK); + + int bytesAppended = 0; + + while (count > 0) { + byte[] block = blocks.get(blockIdx); + int toCopy = Math.min(BLOCK_SIZE - offset, count); + count -= toCopy; + + while (toCopy > 0) { + int bytesRead = is.read(block, offset, toCopy); + + if (bytesRead < 0) { + length -= (count - bytesAppended); + return bytesAppended; + } + + toCopy -= bytesRead; + offset += bytesRead; + } + + blockIdx++; + offset = 0; + } + + return count; + } + + public void getData(OutputStream os, int count, long pos) throws IOException { + if (pos + count > length) { + throw new IndexOutOfBoundsException("Argument out of cache"); + } + + int blockIdx = (int)(pos >> BLOCK_SHIFT); + int offset = (int) (pos & BLOCK_MASK); + if (blockIdx < firstUndisposed) { + throw new IndexOutOfBoundsException("The requested data are already disposed"); + } + + while (count > 0) { + byte[] block = blocks.get(blockIdx); + int toWrite = Math.min(BLOCK_SIZE - offset, count); + os.write(block, offset, toWrite); + + blockIdx++; + offset = 0; + count -= toWrite; + } + } +} diff --git a/app/src/main/java/org/lwjgl/DefaultSysImplementation.java b/app/src/main/java/org/lwjgl/DefaultSysImplementation.java new file mode 100644 index 000000000..924841a23 --- /dev/null +++ b/app/src/main/java/org/lwjgl/DefaultSysImplementation.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2002-2008 LWJGL Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'LWJGL' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.lwjgl; + + +/** + * + * @author elias_naur + * @version $Revision$ + * $Id$ + */ +abstract class DefaultSysImplementation implements SysImplementation { + public /* native */ int getJNIVersion() { + // Bypass JNI Version check. + return getRequiredJNIVersion(); + } + + public /* native */ int getPointerSize() { + return 1; + } + public native void setDebug(boolean debug); + + public long getTimerResolution() { + return 1000; + } + + public boolean has64Bit() { + return System.getProperty("os.arch").contains("64"); + } + + public abstract long getTime(); + public abstract void alert(String title, String message); + public abstract String getClipboard(); +} diff --git a/app/src/main/java/org/lwjgl/LWJGLUtil.java b/app/src/main/java/org/lwjgl/LWJGLUtil.java new file mode 100644 index 000000000..978233bff --- /dev/null +++ b/app/src/main/java/org/lwjgl/LWJGLUtil.java @@ -0,0 +1,621 @@ +/* + * Copyright (c) 2002-2008 LWJGL Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'LWJGL' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.lwjgl; + +import java.io.File; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.nio.ByteBuffer; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.*; + +/** + *

    + * Internal library methods + *

    + * + * @author Brian Matzon + * @version $Revision$ + * $Id$ + */ +public class LWJGLUtil { + public static final int PLATFORM_LINUX = 1; + public static final int PLATFORM_MACOSX = 2; + public static final int PLATFORM_WINDOWS = 3; + public static final int PLATFORM_ANDROID = 1337; + public static final String PLATFORM_LINUX_NAME = "linux"; + public static final String PLATFORM_MACOSX_NAME = "macosx"; + public static final String PLATFORM_WINDOWS_NAME = "windows"; + public static final String PLATFORM_ANDROID_NAME = "android"; + + private static final String LWJGL_ICON_DATA_16x16 = + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + + "\377\377\377\377\377\377\377\377\376\377\377\377\302\327\350\377" + + "\164\244\313\377\120\213\275\377\124\216\277\377\206\257\322\377" + + "\347\357\366\377\377\377\377\377\377\377\377\377\377\377\377\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + + "\377\377\377\377\365\365\365\377\215\217\221\377\166\202\215\377" + + "\175\215\233\377\204\231\252\377\224\267\325\377\072\175\265\377" + + "\110\206\272\377\332\347\361\377\377\377\377\377\377\377\377\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + + "\364\370\373\377\234\236\240\377\000\000\000\377\000\000\000\377" + + "\000\000\000\377\000\000\000\377\344\344\344\377\204\255\320\377" + + "\072\175\265\377\133\222\301\377\374\375\376\377\377\377\377\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + + "\221\266\325\377\137\137\137\377\000\000\000\377\000\000\000\377" + + "\000\000\000\377\042\042\042\377\377\377\377\377\350\360\366\377" + + "\071\174\265\377\072\175\265\377\304\330\351\377\377\377\377\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\306\331\351\377" + + "\201\253\316\377\035\035\035\377\000\000\000\377\000\000\000\377" + + "\000\000\000\377\146\146\146\377\377\377\377\377\320\340\355\377" + + "\072\175\265\377\072\175\265\377\215\264\324\377\377\377\377\377" + + "\362\362\362\377\245\245\245\377\337\337\337\377\242\301\334\377" + + "\260\305\326\377\012\012\012\377\000\000\000\377\000\000\000\377" + + "\000\000\000\377\250\250\250\377\377\377\377\377\227\272\330\377" + + "\072\175\265\377\072\175\265\377\161\241\312\377\377\377\377\377" + + "\241\241\241\377\000\000\000\377\001\001\001\377\043\043\043\377" + + "\314\314\314\377\320\320\320\377\245\245\245\377\204\204\204\377" + + "\134\134\134\377\357\357\357\377\377\377\377\377\140\226\303\377" + + "\072\175\265\377\072\175\265\377\155\236\310\377\377\377\377\377" + + "\136\136\136\377\000\000\000\377\000\000\000\377\000\000\000\377" + + "\317\317\317\377\037\037\037\377\003\003\003\377\053\053\053\377" + + "\154\154\154\377\306\306\306\377\372\374\375\377\236\277\332\377" + + "\167\245\314\377\114\211\274\377\174\250\316\377\377\377\377\377" + + "\033\033\033\377\000\000\000\377\000\000\000\377\027\027\027\377" + + "\326\326\326\377\001\001\001\377\000\000\000\377\000\000\000\377" + + "\000\000\000\377\122\122\122\377\345\345\345\377\075\075\075\377" + + "\150\150\150\377\246\246\247\377\332\336\341\377\377\377\377\377" + + "\164\164\164\377\016\016\016\377\000\000\000\377\131\131\131\377" + + "\225\225\225\377\000\000\000\377\000\000\000\377\000\000\000\377" + + "\000\000\000\377\221\221\221\377\233\233\233\377\000\000\000\377" + + "\000\000\000\377\000\000\000\377\002\002\002\377\103\103\103\377" + + "\377\377\377\377\356\356\356\377\214\214\214\377\277\277\277\377" + + "\126\126\126\377\000\000\000\377\000\000\000\377\000\000\000\377" + + "\000\000\000\377\323\323\323\377\130\130\130\377\000\000\000\377" + + "\000\000\000\377\000\000\000\377\000\000\000\377\063\063\063\377" + + "\377\377\377\377\377\377\377\377\374\375\376\377\377\377\377\377" + + "\300\300\300\377\100\100\100\377\002\002\002\377\000\000\000\377" + + "\033\033\033\377\373\373\373\377\027\027\027\377\000\000\000\377" + + "\000\000\000\377\000\000\000\377\000\000\000\377\170\170\170\377" + + "\377\377\377\377\377\377\377\377\322\341\356\377\176\251\316\377" + + "\340\352\363\377\377\377\377\377\324\324\324\377\155\155\155\377" + + "\204\204\204\377\323\323\323\377\000\000\000\377\000\000\000\377" + + "\000\000\000\377\000\000\000\377\000\000\000\377\275\275\275\377" + + "\377\377\377\377\377\377\377\377\376\376\376\377\146\232\305\377" + + "\075\177\266\377\202\254\320\377\344\355\365\377\377\377\377\377" + + "\377\377\377\377\345\345\345\377\055\055\055\377\000\000\000\377" + + "\000\000\000\377\000\000\000\377\014\014\014\377\366\366\366\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\342\354\364\377" + + "\115\211\274\377\072\175\265\377\076\200\266\377\207\260\322\377" + + "\347\357\366\377\377\377\377\377\376\376\376\377\274\274\274\377" + + "\117\117\117\377\003\003\003\377\112\112\112\377\377\377\377\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + + "\353\362\370\377\214\263\324\377\126\220\300\377\120\214\275\377" + + "\167\245\314\377\355\363\370\377\377\377\377\377\377\377\377\377" + + "\377\377\377\377\337\337\337\377\346\346\346\377\377\377\377\377"; + + private static final String LWJGL_ICON_DATA_32x32 = + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\372\374\375\377" + + "\313\335\354\377\223\267\326\377\157\240\311\377\134\223\302\377\140\226\303\377\172\247\315\377\254\310\340\377\355\363\370\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\374\375\376\377\265\316\343\377\132\222\301\377" + + "\072\175\265\377\072\175\265\377\072\175\265\377\072\175\265\377\072\175\265\377\072\175\265\377\072\175\265\377\105\205\271\377" + + "\241\301\334\377\374\375\376\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\374\374\374\377\342\352\361\377\270\317\343\377\256\311\340\377" + + "\243\302\334\377\230\272\330\377\214\263\323\377\201\254\317\377\156\237\310\377\075\177\266\377\072\175\265\377\072\175\265\377" + + "\072\175\265\377\162\242\312\377\365\370\373\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\330\330\330\377\061\061\061\377\044\044\044\377\061\061\061\377\100\100\100\377" + + "\122\122\122\377\145\145\145\377\164\164\164\377\217\217\217\377\367\370\370\377\254\310\337\377\073\175\265\377\072\175\265\377" + + "\072\175\265\377\072\175\265\377\171\247\315\377\374\375\376\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + + "\377\377\377\377\377\377\377\377\376\376\376\377\150\150\150\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" + + "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\266\266\266\377\376\376\376\377\206\256\321\377\072\175\265\377" + + "\072\175\265\377\072\175\265\377\072\175\265\377\256\312\341\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + + "\377\377\377\377\323\342\356\377\341\352\362\377\050\050\050\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" + + "\000\000\000\377\000\000\000\377\000\000\000\377\002\002\002\377\336\336\336\377\377\377\377\377\365\370\373\377\133\222\301\377" + + "\072\175\265\377\072\175\265\377\072\175\265\377\110\206\272\377\364\370\373\377\377\377\377\377\377\377\377\377\377\377\377\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + + "\354\363\370\377\144\231\305\377\327\331\333\377\005\005\005\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" + + "\000\000\000\377\000\000\000\377\000\000\000\377\044\044\044\377\376\376\376\377\377\377\377\377\377\377\377\377\300\325\347\377" + + "\071\174\265\377\072\175\265\377\072\175\265\377\072\175\265\377\253\310\340\377\377\377\377\377\377\377\377\377\377\377\377\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\376\377\377\377" + + "\170\246\314\377\173\247\315\377\236\236\236\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" + + "\000\000\000\377\000\000\000\377\000\000\000\377\145\145\145\377\377\377\377\377\377\377\377\377\377\377\377\377\342\354\364\377" + + "\067\173\264\377\072\175\265\377\072\175\265\377\072\175\265\377\146\232\305\377\377\377\377\377\377\377\377\377\377\377\377\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\303\327\350\377" + + "\071\175\265\377\262\314\341\377\130\130\130\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" + + "\000\000\000\377\000\000\000\377\000\000\000\377\251\251\251\377\377\377\377\377\377\377\377\377\377\377\377\377\274\322\345\377" + + "\072\175\265\377\072\175\265\377\072\175\265\377\072\175\265\377\100\201\267\377\356\364\371\377\377\377\377\377\377\377\377\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\372\374\375\377\132\222\301\377" + + "\075\177\266\377\335\345\355\377\034\034\034\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" + + "\000\000\000\377\000\000\000\377\007\007\007\377\347\347\347\377\377\377\377\377\377\377\377\377\377\377\377\377\205\256\321\377" + + "\072\175\265\377\072\175\265\377\072\175\265\377\072\175\265\377\071\175\265\377\314\336\354\377\377\377\377\377\377\377\377\377" + + "\377\377\377\377\377\377\377\377\376\376\376\377\377\377\377\377\377\377\377\377\377\377\377\377\272\322\345\377\072\175\265\377" + + "\127\220\277\377\320\321\321\377\003\003\003\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" + + "\000\000\000\377\000\000\000\377\063\063\063\377\375\375\375\377\377\377\377\377\377\377\377\377\373\374\375\377\120\213\275\377" + + "\072\175\265\377\072\175\265\377\072\175\265\377\072\175\265\377\071\175\265\377\261\314\342\377\377\377\377\377\377\377\377\377" + + "\377\377\377\377\312\312\312\377\067\067\067\377\141\141\141\377\242\242\242\377\335\335\335\377\344\354\363\377\261\313\341\377" + + "\264\315\342\377\346\346\346\377\043\043\043\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" + + "\000\000\000\377\000\000\000\377\162\162\162\377\377\377\377\377\377\377\377\377\377\377\377\377\330\345\360\377\072\175\265\377" + + "\072\175\265\377\072\175\265\377\072\175\265\377\072\175\265\377\072\175\265\377\240\300\333\377\377\377\377\377\377\377\377\377" + + "\377\377\377\377\146\146\146\377\000\000\000\377\000\000\000\377\000\000\000\377\006\006\006\377\047\047\047\377\146\146\146\377" + + "\324\324\324\377\377\377\377\377\366\366\366\377\320\320\320\377\227\227\227\377\136\136\136\377\047\047\047\377\004\004\004\377" + + "\000\000\000\377\003\003\003\377\300\300\300\377\377\377\377\377\377\377\377\377\377\377\377\377\242\301\333\377\072\175\265\377" + + "\072\175\265\377\072\175\265\377\072\175\265\377\072\175\265\377\072\175\265\377\236\277\332\377\377\377\377\377\377\377\377\377" + + "\373\373\373\377\045\045\045\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" + + "\134\134\134\377\377\377\377\377\352\352\352\377\217\217\217\377\265\265\265\377\351\351\351\377\375\375\375\377\347\347\347\377" + + "\262\262\262\377\275\275\275\377\376\376\376\377\377\377\377\377\377\377\377\377\377\377\377\377\153\235\307\377\072\175\265\377" + + "\072\175\265\377\072\175\265\377\072\175\265\377\072\175\265\377\072\175\265\377\241\301\334\377\377\377\377\377\377\377\377\377" + + "\333\333\333\377\003\003\003\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" + + "\203\203\203\377\377\377\377\377\137\137\137\377\000\000\000\377\000\000\000\377\013\013\013\377\067\067\067\377\166\166\166\377" + + "\267\267\267\377\360\360\360\377\377\377\377\377\377\377\377\377\377\377\377\377\360\365\371\377\113\210\273\377\075\177\266\377" + + "\071\174\265\377\072\175\265\377\072\175\265\377\072\175\265\377\072\175\265\377\262\314\342\377\377\377\377\377\377\377\377\377" + + "\232\232\232\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" + + "\305\305\305\377\367\367\367\377\035\035\035\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" + + "\000\000\000\377\007\007\007\377\074\074\074\377\337\337\337\377\377\377\377\377\373\374\375\377\374\375\376\377\363\367\372\377" + + "\314\335\353\377\236\276\332\377\162\241\311\377\114\211\273\377\072\175\265\377\311\334\353\377\377\377\377\377\377\377\377\377" + + "\126\126\126\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\017\017\017\377" + + "\371\371\371\377\321\321\321\377\003\003\003\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" + + "\000\000\000\377\000\000\000\377\000\000\000\377\216\216\216\377\377\377\377\377\371\371\371\377\204\204\204\377\160\160\160\377" + + "\260\260\260\377\352\352\352\377\377\377\377\377\371\373\374\377\334\350\362\377\366\371\374\377\377\377\377\377\377\377\377\377" + + "\025\025\025\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\116\116\116\377" + + "\377\377\377\377\221\221\221\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" + + "\000\000\000\377\000\000\000\377\000\000\000\377\273\273\273\377\377\377\377\377\236\236\236\377\000\000\000\377\000\000\000\377" + + "\000\000\000\377\004\004\004\377\057\057\057\377\160\160\160\377\260\260\260\377\346\346\346\377\376\376\376\377\377\377\377\377" + + "\071\071\071\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\220\220\220\377" + + "\377\377\377\377\115\115\115\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" + + "\000\000\000\377\000\000\000\377\020\020\020\377\360\360\360\377\377\377\377\377\132\132\132\377\000\000\000\377\000\000\000\377" + + "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\011\011\011\377\062\062\062\377\261\261\261\377" + + "\366\366\366\377\241\241\241\377\065\065\065\377\002\002\002\377\000\000\000\377\000\000\000\377\002\002\002\377\321\321\321\377" + + "\365\365\365\377\023\023\023\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" + + "\000\000\000\377\000\000\000\377\105\105\105\377\376\376\376\377\370\370\370\377\035\035\035\377\000\000\000\377\000\000\000\377" + + "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\053\053\053\377" + + "\377\377\377\377\377\377\377\377\374\374\374\377\276\276\276\377\120\120\120\377\005\005\005\377\045\045\045\377\371\371\371\377" + + "\302\302\302\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" + + "\000\000\000\377\000\000\000\377\206\206\206\377\377\377\377\377\322\322\322\377\001\001\001\377\000\000\000\377\000\000\000\377" + + "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\103\103\103\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\376\376\376\377\334\334\334\377\340\340\340\377\377\377\377\377" + + "\225\225\225\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" + + "\000\000\000\377\001\001\001\377\310\310\310\377\377\377\377\377\216\216\216\377\000\000\000\377\000\000\000\377\000\000\000\377" + + "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\210\210\210\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + + "\337\337\337\377\051\051\051\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" + + "\000\000\000\377\030\030\030\377\365\365\365\377\377\377\377\377\112\112\112\377\000\000\000\377\000\000\000\377\000\000\000\377" + + "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\317\317\317\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\361\366\372\377\377\377\377\377\377\377\377\377" + + "\377\377\377\377\371\371\371\377\265\265\265\377\113\113\113\377\006\006\006\377\000\000\000\377\000\000\000\377\000\000\000\377" + + "\000\000\000\377\122\122\122\377\377\377\377\377\370\370\370\377\020\020\020\377\000\000\000\377\000\000\000\377\000\000\000\377" + + "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\034\034\034\377\370\370\370\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\206\257\321\377\220\265\325\377\352\361\367\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\333\333\333\377\170\170\170\377\033\033\033\377\000\000\000\377" + + "\000\000\000\377\226\226\226\377\377\377\377\377\306\306\306\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" + + "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\132\132\132\377\377\377\377\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\303\330\351\377\072\175\265\377\103\203\270\377" + + "\224\270\326\377\355\363\370\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\364\364\364\377\247\247\247\377" + + "\205\205\205\377\364\364\364\377\377\377\377\377\206\206\206\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" + + "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\235\235\235\377\377\377\377\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\372\373\375\377\135\224\302\377\072\175\265\377" + + "\072\175\265\377\106\205\271\377\230\273\330\377\357\364\371\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\233\233\233\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377" + + "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\005\005\005\377\335\335\335\377\377\377\377\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\305\331\351\377\073\176\266\377" + + "\072\175\265\377\072\175\265\377\072\175\265\377\110\206\272\377\236\276\332\377\362\366\372\377\377\377\377\377\377\377\377\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\373\373\373\377\216\216\216\377\045\045\045\377\001\001\001\377\000\000\000\377" + + "\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\054\054\054\377\374\374\374\377\377\377\377\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\217\265\325\377" + + "\072\175\265\377\072\175\265\377\072\175\265\377\072\175\265\377\072\175\265\377\112\207\273\377\243\302\334\377\363\367\372\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\372\372\372\377\260\260\260\377\105\105\105\377" + + "\004\004\004\377\000\000\000\377\000\000\000\377\000\000\000\377\000\000\000\377\156\156\156\377\377\377\377\377\377\377\377\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\374\375\376\377" + + "\205\257\321\377\072\175\265\377\072\175\265\377\072\175\265\377\072\175\265\377\072\175\265\377\072\175\265\377\115\211\274\377" + + "\250\305\336\377\366\371\374\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\376\376\376\377" + + "\322\322\322\377\150\150\150\377\016\016\016\377\000\000\000\377\001\001\001\377\270\270\270\377\377\377\377\377\377\377\377\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + + "\376\376\377\377\261\313\342\377\114\211\274\377\071\175\265\377\072\175\265\377\072\175\265\377\072\175\265\377\072\175\265\377" + + "\072\175\265\377\115\211\274\377\277\324\347\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + + "\377\377\377\377\377\377\377\377\354\354\354\377\223\223\223\377\233\233\233\377\375\375\375\377\377\377\377\377\377\377\377\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + + "\377\377\377\377\377\377\377\377\363\367\372\377\265\316\343\377\201\254\320\377\145\231\305\377\141\227\304\377\154\236\310\377" + + "\217\265\325\377\305\331\351\377\367\372\374\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"; + + /** LWJGL Logo - 16 by 16 pixels */ + public static final ByteBuffer LWJGLIcon16x16 = loadIcon(LWJGL_ICON_DATA_16x16); + + /** LWJGL Logo - 32 by 32 pixels */ + public static final ByteBuffer LWJGLIcon32x32 = loadIcon(LWJGL_ICON_DATA_32x32); + + /** Debug flag. */ + public static final boolean DEBUG = true;/*getPrivilegedBoolean("org.lwjgl.util.Debug");*/ + + public static final boolean CHECKS = !getPrivilegedBoolean("org.lwjgl.util.NoChecks"); + + private static final int PLATFORM; + + static { + /*final String osName = getPrivilegedProperty("os.name"); + if ( osName.startsWith("Windows") ) + PLATFORM = PLATFORM_WINDOWS; + else if ( osName.startsWith("Linux") || osName.startsWith("FreeBSD") || osName.startsWith("SunOS") || osName.startsWith("Unix") ) + PLATFORM = PLATFORM_LINUX; + else if ( osName.startsWith("Mac OS X") || osName.startsWith("Darwin") ) + PLATFORM = PLATFORM_MACOSX; + else + throw new LinkageError("Unknown platform: " + osName);*/ + PLATFORM = PLATFORM_ANDROID; + } + + private static ByteBuffer loadIcon(String data) { + int len = data.length(); + ByteBuffer bb = BufferUtils.createByteBuffer(len); + for(int i=0 ; i possible_paths = new ArrayList(); + + String classloader_path = getPathFromClassLoader(libname, classloader); + if (classloader_path != null) { + log("getPathFromClassLoader: Path found: " + classloader_path); + possible_paths.add(classloader_path); + } + + for ( String platform_lib_name : platform_lib_names ) { + String lwjgl_classloader_path = getPathFromClassLoader("lwjgl", classloader); + if ( lwjgl_classloader_path != null ) { + log("getPathFromClassLoader: Path found: " + lwjgl_classloader_path); + possible_paths.add(lwjgl_classloader_path.substring(0, lwjgl_classloader_path.lastIndexOf(File.separator)) + + File.separator + platform_lib_name); + } + + // add Installer path + String alternative_path = getPrivilegedProperty("org.lwjgl.librarypath"); + if ( alternative_path != null ) { + possible_paths.add(alternative_path + File.separator + platform_lib_name); + } + + // Add all possible paths from java.library.path + String java_library_path = getPrivilegedProperty("java.library.path"); + + StringTokenizer st = new StringTokenizer(java_library_path, File.pathSeparator); + while ( st.hasMoreTokens() ) { + String path = st.nextToken(); + possible_paths.add(path + File.separator + platform_lib_name); + } + + //add current path + String current_dir = getPrivilegedProperty("user.dir"); + possible_paths.add(current_dir + File.separator + platform_lib_name); + + //add pure library (no path, let OS search) + possible_paths.add(platform_lib_name); + } + + //create needed string array + return possible_paths.toArray(new String[possible_paths.size()]); + } + + static void execPrivileged(final String[] cmd_array) throws Exception { + try { + Process process = AccessController.doPrivileged(new PrivilegedExceptionAction() { + public Process run() throws Exception { + return Runtime.getRuntime().exec(cmd_array); + } + }); + // Close unused streams to make sure the child process won't hang + process.getInputStream().close(); + process.getOutputStream().close(); + process.getErrorStream().close(); + } catch (PrivilegedActionException e) { + throw (Exception)e.getCause(); + } + } + + private static String getPrivilegedProperty(final String property_name) { + return AccessController.doPrivileged(new PrivilegedAction() { + public String run() { + return System.getProperty(property_name); + } + }); + } + + /** + * Tries to locate named library from the current ClassLoader + * This method exists because native libraries are loaded from native code, and as such + * is exempt from ClassLoader library loading rutines. It therefore always fails. + * We therefore invoke the protected method of the ClassLoader to see if it can + * locate it. + * + * @param libname Name of library to search for + * @param classloader Classloader to use + * @return Absolute path to library if found, otherwise null + */ + private static String getPathFromClassLoader(final String libname, final ClassLoader classloader) { + Class c = null; + + try { + log("getPathFromClassLoader: searching for: " + libname); + c = classloader.getClass(); + while (c != null) { + final Class clazz = c; + try { + return AccessController.doPrivileged(new PrivilegedExceptionAction() { + public String run() throws Exception { + Method findLibrary = clazz.getDeclaredMethod("findLibrary", String.class); + findLibrary.setAccessible(true); + String path = (String)findLibrary.invoke(classloader, libname); + return path; + } + }); + } catch (PrivilegedActionException e) { + log("Failed to locate findLibrary method: " + e.getCause()); + c = c.getSuperclass(); + } + } + } catch (Exception e) { + log("Failure locating " + e + " using classloader:" + c); + } + return null; + } + + /** + * Gets a boolean property as a privileged action. + */ + public static boolean getPrivilegedBoolean(final String property_name) { + return AccessController.doPrivileged(new PrivilegedAction() { + public Boolean run() { + return Boolean.getBoolean(property_name); + } + }); + } + + /** + * Gets an integer property as a privileged action. + * + * @param property_name the integer property name + * + * @return the property value + */ + public static Integer getPrivilegedInteger(final String property_name) { + return AccessController.doPrivileged(new PrivilegedAction() { + public Integer run() { + return Integer.getInteger(property_name); + } + }); + } + + /** + * Gets an integer property as a privileged action. + * + * @param property_name the integer property name + * @param default_val the default value to use if the property is not defined + * + * @return the property value + */ + public static Integer getPrivilegedInteger(final String property_name, final int default_val) { + return AccessController.doPrivileged(new PrivilegedAction() { + public Integer run() { + return Integer.getInteger(property_name, default_val); + } + }); + } + + /** + * Prints the given message to System.err if DEBUG is true. + * + * @param msg Message to print + */ + public static void log(CharSequence msg) { + if (DEBUG) { + System.err.println("[LWJGL] " + msg); + } + } + + /** + * Method to determine if the current system is running a version of + * Mac OS X better than the given version. This is only useful for Mac OS X + * specific code and will not work for any other platform. + */ + public static boolean isMacOSXEqualsOrBetterThan(int major_required, int minor_required) { + String os_version = getPrivilegedProperty("os.version"); + StringTokenizer version_tokenizer = new StringTokenizer(os_version, "."); + int major; + int minor; + try { + String major_str = version_tokenizer.nextToken(); + String minor_str = version_tokenizer.nextToken(); + major = Integer.parseInt(major_str); + minor = Integer.parseInt(minor_str); + } catch (Exception e) { + LWJGLUtil.log("Exception occurred while trying to determine OS version: " + e); + // Best guess, no + return false; + } + return major > major_required || (major == major_required && minor >= minor_required); + } + + /** + * Returns a map of public static final integer fields in the specified classes, to their String representations. + * An optional filter can be specified to only include specific fields. The target map may be null, in which + * case a new map is allocated and returned. + *

    + * This method is useful when debugging to quickly identify values returned from the AL/GL/CL APIs. + * + * @param filter the filter to use (optional) + * @param target the target map (optional) + * @param tokenClasses an array of classes to get tokens from + * + * @return the token map + */ + + public static Map getClassTokens(final TokenFilter filter, final Map target, final Class ... tokenClasses) { + return getClassTokens(filter, target, Arrays.asList(tokenClasses)); + } + + /** + * Returns a map of public static final integer fields in the specified classes, to their String representations. + * An optional filter can be specified to only include specific fields. The target map may be null, in which + * case a new map is allocated and returned. + *

    + * This method is useful when debugging to quickly identify values returned from the AL/GL/CL APIs. + * + * @param filter the filter to use (optional) + * @param target the target map (optional) + * @param tokenClasses the classes to get tokens from + * + * @return the token map + */ + public static Map getClassTokens(final TokenFilter filter, Map target, final Iterable tokenClasses) { + if ( target == null ) + target = new HashMap(); + + final int TOKEN_MODIFIERS = Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL; + + for ( final Class tokenClass : tokenClasses ) { + for ( final Field field : tokenClass.getDeclaredFields() ) { + // Get only fields. + if ( (field.getModifiers() & TOKEN_MODIFIERS) == TOKEN_MODIFIERS && field.getType() == int.class ) { + try { + final int value = field.getInt(null); + if ( filter != null && !filter.accept(field, value) ) + continue; + + if ( target.containsKey(value) ) // Print colliding tokens in their hex representation. + target.put(value, toHexString(value)); + else + target.put(value, field.getName()); + } catch (IllegalAccessException e) { + // Ignore + } + } + } + } + + return target; + } + + /** + * Returns a string representation of the integer argument as an + * unsigned integer in base 16. The string will be uppercase + * and will have a leading '0x'. + * + * @param value the integer value + * + * @return the hex string representation + */ + public static String toHexString(final int value) { + return "0x" + Integer.toHexString(value).toUpperCase(); + } + + /** Simple interface for Field filtering. */ + public interface TokenFilter { + + /** + * Should return true if the specified Field passes the filter. + * + * @param field the Field to test + * @param value the integer value of the field + * + * @result true if the Field is accepted + */ + boolean accept(Field field, int value); + + } + +} diff --git a/app/src/main/res/layout/main.xml b/app/src/main/res/layout/main.xml index b9c27da06..81b15c5e7 100644 --- a/app/src/main/res/layout/main.xml +++ b/app/src/main/res/layout/main.xml @@ -115,6 +115,13 @@ + + + android:id="@+id/nav_debug" + android:title="@string/control_adebug" /> + android:id="@+id/nav_customkey" + android:title="@string/control_customkey" /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9688ee64d..d615be057 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -146,7 +146,10 @@ Force close Log output - + PointerCapture Debug + Send custom keycode + +