提交 eee02e51 编写于 作者: R robm

Merge

......@@ -71,8 +71,20 @@ class CAccessibility implements PropertyChangeListener {
}
public void propertyChange(final PropertyChangeEvent evt) {
if (evt.getNewValue() == null) return;
focusChanged();
Object newValue = evt.getNewValue();
if (newValue == null) return;
// Don't post focus on things that don't matter, i.e. alert, colorchooser,
// desktoppane, dialog, directorypane, filechooser, filler, fontchoose,
// frame, glasspane, layeredpane, optionpane, panel, rootpane, separator,
// tooltip, viewport, window.
// List taken from initializeRoles() in JavaComponentUtilities.m.
if (newValue instanceof Accessible) {
AccessibleContext nvAC = ((Accessible) newValue).getAccessibleContext();
AccessibleRole nvRole = nvAC.getAccessibleRole();
if (!ignoredRoles.contains(roleKey(nvRole))) {
focusChanged();
}
}
}
private native void focusChanged();
......@@ -702,9 +714,15 @@ class CAccessibility implements PropertyChangeListener {
if (context == null) continue;
if (whichChildren == JAVA_AX_VISIBLE_CHILDREN) {
if (!context.getAccessibleComponent().isVisible()) continue;
AccessibleComponent acomp = context.getAccessibleComponent();
if (acomp == null || !acomp.isVisible()) {
continue;
}
} else if (whichChildren == JAVA_AX_SELECTED_CHILDREN) {
if (!ac.getAccessibleSelection().isAccessibleChildSelected(i)) continue;
AccessibleSelection sel = ac.getAccessibleSelection();
if (sel == null || !sel.isAccessibleChildSelected(i)) {
continue;
}
}
if (!allowIgnored) {
......
......@@ -40,7 +40,10 @@ import javax.swing.event.ChangeListener;
import static javax.accessibility.AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY;
import static javax.accessibility.AccessibleContext.ACCESSIBLE_CARET_PROPERTY;
import static javax.accessibility.AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY;
import static javax.accessibility.AccessibleContext.ACCESSIBLE_STATE_PROPERTY;
import static javax.accessibility.AccessibleContext.ACCESSIBLE_TEXT_PROPERTY;
import javax.accessibility.AccessibleRole;
import javax.accessibility.AccessibleState;
class CAccessible extends CFRetainedResource implements Accessible {
......@@ -77,6 +80,9 @@ class CAccessible extends CFRetainedResource implements Accessible {
private static native void valueChanged(long ptr);
private static native void selectedTextChanged(long ptr);
private static native void selectionChanged(long ptr);
private static native void menuOpened(long ptr);
private static native void menuClosed(long ptr);
private static native void menuItemSelected(long ptr);
private Accessible accessible;
......@@ -125,16 +131,45 @@ class CAccessible extends CFRetainedResource implements Accessible {
public void propertyChange(PropertyChangeEvent e) {
String name = e.getPropertyName();
if ( ptr != 0 ) {
Object newValue = e.getNewValue();
Object oldValue = e.getOldValue();
if (name.compareTo(ACCESSIBLE_CARET_PROPERTY) == 0) {
selectedTextChanged(ptr);
} else if (name.compareTo(ACCESSIBLE_TEXT_PROPERTY) == 0 ) {
valueChanged(ptr);
} else if (name.compareTo(ACCESSIBLE_SELECTION_PROPERTY) == 0 ) {
selectionChanged(ptr);
} else if (name.compareTo(ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY) == 0 ) {
Object nv = e.getNewValue();
if (nv instanceof AccessibleContext) {
activeDescendant = (AccessibleContext)nv;
} else if (name.compareTo(ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY) == 0 ) {
if (newValue instanceof AccessibleContext) {
activeDescendant = (AccessibleContext)newValue;
}
} else if (name.compareTo(ACCESSIBLE_STATE_PROPERTY) == 0) {
AccessibleContext thisAC = accessible.getAccessibleContext();
AccessibleRole thisRole = thisAC.getAccessibleRole();
Accessible parentAccessible = thisAC.getAccessibleParent();
AccessibleRole parentRole = null;
if (parentAccessible != null) {
parentRole = parentAccessible.getAccessibleContext().getAccessibleRole();
}
// At least for now don't handle combo box menu state changes.
// This may change when later fixing issues which currently
// exist for combo boxes, but for now the following is only
// for JPopupMenus, not for combobox menus.
if (parentRole != AccessibleRole.COMBO_BOX) {
if (thisRole == AccessibleRole.POPUP_MENU) {
if ( newValue != null &&
((AccessibleState)newValue) == AccessibleState.VISIBLE ) {
menuOpened(ptr);
} else if ( oldValue != null &&
((AccessibleState)oldValue) == AccessibleState.VISIBLE ) {
menuClosed(ptr);
}
} else if (thisRole == AccessibleRole.MENU_ITEM) {
if ( newValue != null &&
((AccessibleState)newValue) == AccessibleState.FOCUSED ) {
menuItemSelected(ptr);
}
}
}
}
}
......
......@@ -66,7 +66,6 @@ static JNF_CLASS_CACHE(sjc_CAccessible, "sun/lwawt/macosx/CAccessible");
static JNF_MEMBER_CACHE(jf_ptr, sjc_CAccessible, "ptr", "J");
static JNF_STATIC_MEMBER_CACHE(sjm_getCAccessible, sjc_CAccessible, "getCAccessible", "(Ljavax/accessibility/Accessible;)Lsun/lwawt/macosx/CAccessible;");
static jobject sAccessibilityClass = NULL;
// sAttributeNamesForRoleCache holds the names of the attributes to which each java
......@@ -213,6 +212,24 @@ static NSObject *sAttributeNamesLOCK = nil;
NSAccessibilityPostNotification(self, NSAccessibilitySelectedChildrenChangedNotification);
}
- (void)postMenuOpened
{
AWT_ASSERT_APPKIT_THREAD;
NSAccessibilityPostNotification(self, (NSString *)kAXMenuOpenedNotification);
}
- (void)postMenuClosed
{
AWT_ASSERT_APPKIT_THREAD;
NSAccessibilityPostNotification(self, (NSString *)kAXMenuClosedNotification);
}
- (void)postMenuItemSelected
{
AWT_ASSERT_APPKIT_THREAD;
NSAccessibilityPostNotification(self, (NSString *)kAXMenuItemSelectedNotification);
}
- (BOOL)isEqual:(id)anObject
{
if (![anObject isKindOfClass:[self class]]) return NO;
......@@ -278,8 +295,7 @@ static NSObject *sAttributeNamesLOCK = nil;
+ (jobject) getCAccessible:(jobject)jaccessible withEnv:(JNIEnv *)env {
if (JNFIsInstanceOf(env, jaccessible, &sjc_CAccessible)) {
return jaccessible;
}
else if (JNFIsInstanceOf(env, jaccessible, &sjc_Accessible)) {
} else if (JNFIsInstanceOf(env, jaccessible, &sjc_Accessible)) {
return JNFCallStaticObjectMethod(env, sjm_getCAccessible, jaccessible);
}
return NULL;
......@@ -368,6 +384,14 @@ static NSObject *sAttributeNamesLOCK = nil;
// must init freshly -alloc'd object
[newChild initWithParent:parent withEnv:env withAccessible:jCAX withIndex:index withView:view withJavaRole:javaRole]; // must init new instance
// If creating a JPopupMenu (not a combobox popup list) need to fire menuOpened.
// This is the only way to know if the menu is opening; visible state change
// can't be caught because the listeners are not set up in time.
if ( [javaRole isEqualToString:@"popupmenu"] &&
![[parent javaRole] isEqualToString:@"combobox"] ) {
[newChild postMenuOpened];
}
// must hard retain pointer poked into Java object
[newChild retain];
JNFSetLongField(env, jCAX, jf_ptr, ptr_to_jlong(newChild));
......@@ -634,6 +658,15 @@ static NSObject *sAttributeNamesLOCK = nil;
return moreNames;
}
}
// popupmenu's return values not selected children
if ( [javaRole isEqualToString:@"popupmenu"] &&
![[[self parent] javaRole] isEqualToString:@"combobox"] ) {
NSMutableArray *moreNames =
[[NSMutableArray alloc] initWithCapacity: [names count] + 1];
[moreNames addObjectsFromArray: names];
[moreNames addObject:NSAccessibilityValueAttribute];
return moreNames;
}
return names;
} // end @synchronized
......@@ -707,6 +740,7 @@ static NSObject *sAttributeNamesLOCK = nil;
return value;
}
- (BOOL)accessibilityIsChildrenAttributeSettable
{
return NO;
......@@ -939,6 +973,13 @@ static NSObject *sAttributeNamesLOCK = nil;
if (fNSRole == nil) {
NSString *javaRole = [self javaRole];
fNSRole = [sRoles objectForKey:javaRole];
// The sRoles NSMutableDictionary maps popupmenu to Mac's popup button.
// JComboBox behavior currently relies on this. However this is not the
// proper mapping for a JPopupMenu so fix that.
if ( [javaRole isEqualToString:@"popupmenu"] &&
![[[self parent] javaRole] isEqualToString:@"combobox"] ) {
fNSRole = NSAccessibilityMenuRole;
}
if (fNSRole == nil) {
// this component has assigned itself a custom AccessibleRole not in the sRoles array
fNSRole = javaRole;
......@@ -947,6 +988,7 @@ static NSObject *sAttributeNamesLOCK = nil;
}
return fNSRole;
}
- (BOOL)accessibilityIsRoleAttributeSettable
{
return NO;
......@@ -1046,8 +1088,7 @@ static NSObject *sAttributeNamesLOCK = nil;
- (NSString *)accessibilitySubroleAttribute
{
NSString *value = nil;
if ([[self javaRole] isEqualToString:@"passwordtext"])
{
if ([[self javaRole] isEqualToString:@"passwordtext"]) {
value = NSAccessibilitySecureTextFieldSubrole;
}
/*
......@@ -1123,6 +1164,45 @@ static NSObject *sAttributeNamesLOCK = nil;
JNIEnv* env = [ThreadUtilities getJNIEnv];
// Need to handle popupmenus differently.
//
// At least for now don't handle combo box menus.
// This may change when later fixing issues which currently
// exist for combo boxes, but for now the following is only
// for JPopupMenus, not for combobox menus.
id parent = [self parent];
if ( [[self javaRole] isEqualToString:@"popupmenu"] &&
![[parent javaRole] isEqualToString:@"combobox"] ) {
NSArray *children =
[JavaComponentAccessibility childrenOfParent:self
withEnv:env
withChildrenCode:JAVA_AX_ALL_CHILDREN
allowIgnored:YES];
if ([children count] > 0) {
// handle case of AXMenuItem
// need to ask menu what is selected
NSArray *selectedChildrenOfMenu =
[self accessibilitySelectedChildrenAttribute];
JavaComponentAccessibility *selectedMenuItem =
[selectedChildrenOfMenu objectAtIndex:0];
if (selectedMenuItem != nil) {
jobject itemValue =
JNFCallStaticObjectMethod( env,
sjm_getAccessibleName,
selectedMenuItem->fAccessible,
selectedMenuItem->fComponent ); // AWT_THREADING Safe (AWTRunLoop)
if (itemValue == NULL) {
return nil;
}
NSString* itemString = JNFJavaToNSString(env, itemValue);
(*env)->DeleteLocalRef(env, itemValue);
return itemString;
} else {
return nil;
}
}
}
// ask Java for the component's accessibleValue. In java, the "accessibleValue" just means a numerical value
// a text value is taken care of in JavaTextAccessibility
......@@ -1343,6 +1423,54 @@ JNF_COCOA_ENTER(env);
JNF_COCOA_EXIT(env);
}
/*
* Class: sun_lwawt_macosx_CAccessible
* Method: menuOpened
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_menuOpened
(JNIEnv *env, jclass jklass, jlong element)
{
JNF_COCOA_ENTER(env);
[ThreadUtilities performOnMainThread:@selector(postMenuOpened)
on:(JavaComponentAccessibility *)jlong_to_ptr(element)
withObject:nil
waitUntilDone:NO];
JNF_COCOA_EXIT(env);
}
/*
* Class: sun_lwawt_macosx_CAccessible
* Method: menuClosed
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_menuClosed
(JNIEnv *env, jclass jklass, jlong element)
{
JNF_COCOA_ENTER(env);
[ThreadUtilities performOnMainThread:@selector(postMenuClosed)
on:(JavaComponentAccessibility *)jlong_to_ptr(element)
withObject:nil
waitUntilDone:NO];
JNF_COCOA_EXIT(env);
}
/*
* Class: sun_lwawt_macosx_CAccessible
* Method: menuItemSelected
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_menuItemSelected
(JNIEnv *env, jclass jklass, jlong element)
{
JNF_COCOA_ENTER(env);
[ThreadUtilities performOnMainThread:@selector(postMenuItemSelected)
on:(JavaComponentAccessibility *)jlong_to_ptr(element)
withObject:nil
waitUntilDone:NO];
JNF_COCOA_EXIT(env);
}
/*
* Class: sun_lwawt_macosx_CAccessible
* Method: unregisterFromCocoaAXSystem
......
......@@ -3383,15 +3383,18 @@ public class JList<E> extends JComponent implements Scrollable, Accessible
}
public AccessibleSelection getAccessibleSelection() {
return getCurrentAccessibleContext().getAccessibleSelection();
AccessibleContext ac = getCurrentAccessibleContext();
return ac != null ? ac.getAccessibleSelection() : null;
}
public AccessibleText getAccessibleText() {
return getCurrentAccessibleContext().getAccessibleText();
AccessibleContext ac = getCurrentAccessibleContext();
return ac != null ? ac.getAccessibleText() : null;
}
public AccessibleValue getAccessibleValue() {
return getCurrentAccessibleContext().getAccessibleValue();
AccessibleContext ac = getCurrentAccessibleContext();
return ac != null ? ac.getAccessibleValue() : null;
}
......
......@@ -87,6 +87,8 @@ JNIEXPORT void JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_initIDs
IO_fd_fdID = NET_GetFileDescriptorID(env);
CHECK_NULL(IO_fd_fdID);
JNU_CHECK_EXCEPTION(env);
initInetAddressIDs(env);
}
/*
......
......@@ -298,6 +298,8 @@ sun/security/pkcs11/rsa/TestKeyPairGenerator.java solaris-all
# 8151834
sun/security/mscapi/SmallPrimeExponentP.java windows-i586
#8176354
sun/security/ssl/com/sun/net/ssl/internal/ssl/X509KeyManager/PreferredKey.java generic-all
############################################################################
# jdk_sound
......
/*
* Copyright (c) 2014, 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.
*
* 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.
*/
/*
* @test
* @bug 8035653
* @run main/othervm -Xcheck:jni B8035653
* @summary InetAddress.getLocalHost crash
*/
import java.net.*;
import java.util.*;
public class B8035653 {
public static void main(String[] args) throws Exception {
try (DatagramSocket ds = new DatagramSocket();){
ds.getLocalAddress();
} catch (SocketException e) {
e.printStackTrace();
}
}
}
/*
* Copyright (c) 2017, 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.
*
* 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.
*/
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.accessibility.Accessible;
import javax.accessibility.AccessibleContext;
import javax.swing.AbstractListModel;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
/* @test
@bug 8076249
@summary NPE in AccessBridge while editing JList model
@author Mikhail Cherkasov
@run main AccessibleJListChildNPETest
*/
public class AccessibleJListChildNPETest {
private static String[] model = { "1", "2", "3", "4", "5", "6" };
private static JList<String> list;
public static void main(String[] args) throws InvocationTargetException, InterruptedException {
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
final MyModel dataModel = new MyModel(Arrays.asList(model));
list = new JList<>(dataModel);
frame.getContentPane().add(list);
frame.pack();
frame.setVisible(true);
}
});
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
AccessibleContext ac = list.getAccessibleContext();
MyModel model = (MyModel)list.getModel();
Accessible accessibleChild = ac.getAccessibleChild(model.getSize()-1);
model.removeFirst();
accessibleChild.getAccessibleContext().getAccessibleSelection();
accessibleChild.getAccessibleContext().getAccessibleText();
accessibleChild.getAccessibleContext().getAccessibleValue();
}
});
}
protected static class MyModel extends AbstractListModel<String> {
private List<String> items = new ArrayList<>();
MyModel(final List<String> newItems) {
super();
items.addAll(newItems);
fireIntervalAdded(this, 0, getSize() - 1);
}
void removeFirst() {
if(getSize() > 0) {
items.remove(0);
fireIntervalRemoved(this, 0, 0);
}
}
@Override
public int getSize() {
return items.size();
}
@Override
public String getElementAt(int index) {
return items.get(index);
}
}
}
......@@ -38,11 +38,10 @@ import javax.net.ssl.SSLSocketFactory;
/**
* @test
* @bug 8076221
* @bug 8076221 8157035
* @summary Check if weak cipher suites are disabled
* @run main/othervm DisabledAlgorithms default
* @run main/othervm -Djdk.tls.namedGroups="secp256r1,secp192r1"
* DisabledAlgorithms empty
* @run main/othervm DisabledAlgorithms empty
*/
public class DisabledAlgorithms {
......@@ -98,11 +97,6 @@ public class DisabledAlgorithms {
System.out.println("jdk.tls.disabledAlgorithms = "
+ Security.getProperty("jdk.tls.disabledAlgorithms"));
// some of the certs in our test are weak; disable
Security.setProperty("jdk.certpath.disabledAlgorithms", "");
System.out.println("jdk.certpath.disabledAlgorithms = "
+ Security.getProperty("jdk.cerpath.disabledAlgorithms"));
// check if RC4 cipher suites can be used
// if jdk.tls.disabledAlgorithms is empty
checkSuccess(rc4_ciphersuites);
......
Keystores used for the JSSE regression test suite.
keystore
truststore
==========
These are the primary two keystores and contain entries for testing most
of the JSSE regression test files. There are three entries, one RSA-based,
one DSA-based and one EC-based. If they expire, simply recreate them
using keytool and most of the test cases should work.
The password on both files is:
passphrase
There are no individual key entry passwords at this time.
keystore entries
================
Alias name: dummy
-----------------
Creation date: May 16, 2016
Entry type: PrivateKeyEntry
Certificate chain length: 1
Certificate[1]:
Owner: CN=dummy.example.com, OU=Dummy, O=Dummy, L=Cupertino, ST=CA, C=US
Issuer: CN=dummy.example.com, OU=Dummy, O=Dummy, L=Cupertino, ST=CA, C=US
Serial number: 57399b87
Valid from: Mon May 16 10:06:38 UTC 2016 until: Sat May 16 10:06:38 UTC 2026
Signature algorithm name: SHA256withRSA
Version: 1
This can be generated using hacked (update the keytool source code so that
it can be used for version 1 X.509 certificate) keytool command:
% keytool -genkeypair -alias dummy -keyalg RSA -keysize 2048 \
-sigalg SHA256withRSA \
-dname "CN=dummy.example.com, OU=Dummy, O=Dummy, L=Cupertino, ST=CA, C=US" \
-validity 3652 -keypass passphrase -keystore keystore -storepass passphrase
Alias name: dummyecdsa
----------------------
Creation date: May 16, 2016
Entry type: PrivateKeyEntry
Certificate chain length: 1
Certificate[1]:
Owner: CN=dummy.example.com, OU=Dummy, O=Dummy, L=Cupertino, ST=CA, C=US
Issuer: CN=dummy.example.com, OU=Dummy, O=Dummy, L=Cupertino, ST=CA, C=US
Serial number: 57399c1d
Valid from: Mon May 16 10:09:01 UTC 2016 until: Sat May 16 10:09:01 UTC 2026
Signature algorithm name: SHA256withECDSA
Version: 1
This can be generated using hacked (update the keytool source code so that
it can be used for version 1 X.509 certificate) keytool command:
% keytool -genkeypair -alias dummy -keyalg EC -keysize 256 \
-sigalg SHA256withECDSA \
-dname "CN=dummy.example.com, OU=Dummy, O=Dummy, L=Cupertino, ST=CA, C=US" \
-validity 3652 -keypass passphrase -keystore keystore -storepass passphrase
Alias name: dummydsa
--------------------
Creation date: Mar 11, 2007
Entry type: PrivateKeyEntry
Certificate chain length: 1
Certificate[1]:
Owner: CN=dummy.example.com, OU=Dummy, O=Dummy, L=Cupertino, ST=CA, C=US
Issuer: CN=dummy.example.com, OU=Dummy, O=Dummy, L=Cupertino, ST=CA, C=US
Serial number: 45f3a314
Valid from: Sun Mar 11 06:35:00 UTC 2007 until: Wed Mar 08 06:35:00 UTC 2017
Certificate fingerprints:
Signature algorithm name: SHA1withDSA
Version: 1
This can be generated using hacked (update the keytool source code so that
it can be used for version 1 X.509 certificate) keytool command:
% keytool -genkeypair -alias dummy -keyalg DSA -keysize 1024 \
-sigalg SHA1withDSA \
-dname "CN=dummy.example.com, OU=Dummy, O=Dummy, L=Cupertino, ST=CA, C=US" \
-validity 3652 -keypass passphrase -keystore keystore -storepass passphrase
truststore entries
==================
This key store contains only trusted certificate entries. The same
certificates are used in both keystore and truststore.
unknown_keystore
================
A keystore you can use when you don't want things to be verified.
Use this with keystore/truststore, and you'll never get a match.
......@@ -26,8 +26,7 @@
* @bug 4496785
* @summary Verify that all ciphersuites work in all configurations
* @author Andreas Sterbenz
* @run main/othervm/timeout=300 -Djdk.tls.namedGroups="secp256r1,secp192r1"
* ClientJSSEServerJSSE
* @run main/othervm/timeout=300 ClientJSSEServerJSSE
*/
import java.security.Security;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册