| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2011, 2012 Google Inc. All rights reserved. | 2 * Copyright (C) 2011, 2012 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 3033 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3044 ASSERT_EQ(4ul, renders.size()); | 3044 ASSERT_EQ(4ul, renders.size()); |
| 3045 for (size_t i = 0; i < renders.size(); ++i) { | 3045 for (size_t i = 0; i < renders.size(); ++i) { |
| 3046 double docStartTime = frame->domWindow()->document()->loader()->timing()
.monotonicTimeToZeroBasedDocumentTime(renderPairs[i].startTime) * 1000.0; | 3046 double docStartTime = frame->domWindow()->document()->loader()->timing()
.monotonicTimeToZeroBasedDocumentTime(renderPairs[i].startTime) * 1000.0; |
| 3047 ASSERT_DOUBLE_EQ(docStartTime, renders[i]->startTime()); | 3047 ASSERT_DOUBLE_EQ(docStartTime, renders[i]->startTime()); |
| 3048 double docFinishTime = frame->domWindow()->document()->loader()->timing(
).monotonicTimeToZeroBasedDocumentTime(renderPairs[i].finishTime) * 1000.0; | 3048 double docFinishTime = frame->domWindow()->document()->loader()->timing(
).monotonicTimeToZeroBasedDocumentTime(renderPairs[i].finishTime) * 1000.0; |
| 3049 double docDuration = docFinishTime - docStartTime; | 3049 double docDuration = docFinishTime - docStartTime; |
| 3050 ASSERT_DOUBLE_EQ(docDuration, renders[i]->duration()); | 3050 ASSERT_DOUBLE_EQ(docDuration, renders[i]->duration()); |
| 3051 } | 3051 } |
| 3052 } | 3052 } |
| 3053 | 3053 |
| 3054 TEST_F(WebViewTest, MoveFocusToNextFocusableElementInFormWithKeyEventListenersAn
dNonEditableElements) | |
| 3055 { | |
| 3056 const std::string testFile = "advance_focus_in_form_with_key_event_listeners
.html"; | |
| 3057 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c
_str()), WebString::fromUTF8(testFile.c_str())); | |
| 3058 WebView* webViewImpl = m_webViewHelper.initializeAndLoad(m_baseURL + testFil
e, true, nullptr); | |
| 3059 webViewImpl->setInitialFocus(false); | |
| 3060 WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewImpl->mainFrame()); | |
| 3061 HTMLDocument* document = toHTMLDocument(frame->frame()->document()); | |
| 3062 const int defaultTextInputFlags = WebTextInputFlagAutocapitalizeSentences; | |
| 3063 | |
| 3064 struct FocusedElement { | |
| 3065 const char* elementId; | |
| 3066 int textInputFlags; | |
| 3067 } focusedElements[] = { | |
| 3068 {"input1", defaultTextInputFlags | WebTextInputFlagHaveNextFocusableElem
ent}, | |
| 3069 {"contenteditable1", WebTextInputFlagHaveNextFocusableElement | WebTextI
nputFlagHavePreviousFocusableElement}, | |
| 3070 {"input2", defaultTextInputFlags | WebTextInputFlagHaveNextFocusableElem
ent | WebTextInputFlagHavePreviousFocusableElement | WebTextInputFlagListeningTo
KeyboardEvents}, | |
| 3071 {"textarea1", defaultTextInputFlags | WebTextInputFlagHaveNextFocusableE
lement | WebTextInputFlagHavePreviousFocusableElement}, | |
| 3072 {"input3", defaultTextInputFlags | WebTextInputFlagHaveNextFocusableElem
ent | WebTextInputFlagHavePreviousFocusableElement}, | |
| 3073 {"textarea2", defaultTextInputFlags | WebTextInputFlagHavePreviousFocusa
bleElement}, | |
| 3074 }; | |
| 3075 | |
| 3076 // Forward Navigation in form1 with NEXT | |
| 3077 Element* input1 = document->getElementById("input1"); | |
| 3078 input1->focus(); | |
| 3079 Element* currentFocus = nullptr; | |
| 3080 WebTextInputInfo textInputInfo; | |
| 3081 for (size_t i = 0; i < WTF_ARRAY_LENGTH(focusedElements); ++i) { | |
| 3082 currentFocus = document->getElementById(focusedElements[i].elementId); | |
| 3083 EXPECT_EQ(currentFocus, document->focusedElement()); | |
| 3084 textInputInfo = webViewImpl->textInputInfo(); | |
| 3085 EXPECT_EQ(focusedElements[i].textInputFlags, textInputInfo.flags); | |
| 3086 webViewImpl->advanceFocusInForm(WebFocusTypeForward); | |
| 3087 } | |
| 3088 // Now focus will stay on previous focus itself, because it has no next | |
| 3089 // element. | |
| 3090 EXPECT_EQ(currentFocus, document->focusedElement()); | |
| 3091 | |
| 3092 // Backward Navigation in form1 with PREVIOUS | |
| 3093 for (size_t i = WTF_ARRAY_LENGTH(focusedElements); i-- > 0;) { | |
| 3094 currentFocus = document->getElementById(focusedElements[i].elementId); | |
| 3095 EXPECT_EQ(currentFocus, document->focusedElement()); | |
| 3096 textInputInfo = webViewImpl->textInputInfo(); | |
| 3097 EXPECT_EQ(focusedElements[i].textInputFlags, textInputInfo.flags); | |
| 3098 webViewImpl->advanceFocusInForm(WebFocusTypeBackward); | |
| 3099 } | |
| 3100 // Now focus will stay on previous focus itself, because it has no previous | |
| 3101 // element. | |
| 3102 EXPECT_EQ(currentFocus, document->focusedElement()); | |
| 3103 | |
| 3104 // Setting a non editable element as focus in form1, and ensuring editable | |
| 3105 // navigation is fine in forward and backward. | |
| 3106 Element* button1 = document->getElementById("button1"); | |
| 3107 button1->focus(); | |
| 3108 textInputInfo = webViewImpl->textInputInfo(); | |
| 3109 // No Next/Previous element for elements outside form. | |
| 3110 EXPECT_EQ(0, textInputInfo.flags); | |
| 3111 webViewImpl->advanceFocusInForm(WebFocusTypeForward); | |
| 3112 Element* contenteditable1 = document->getElementById("contenteditable1"); | |
| 3113 EXPECT_EQ(contenteditable1, document->focusedElement()); | |
| 3114 button1->focus(); | |
| 3115 webViewImpl->advanceFocusInForm(WebFocusTypeBackward); | |
| 3116 EXPECT_EQ(input1, document->focusedElement()); | |
| 3117 | |
| 3118 Element* anchor1 = document->getElementById("anchor1"); | |
| 3119 anchor1->focus(); | |
| 3120 textInputInfo = webViewImpl->textInputInfo(); | |
| 3121 // No Next/Previous element for elements outside form. | |
| 3122 EXPECT_EQ(0, textInputInfo.flags); | |
| 3123 webViewImpl->advanceFocusInForm(WebFocusTypeForward); | |
| 3124 // Since anchor is not a form control element, next/previous element will | |
| 3125 // be null, hence focus will stay same as it is. | |
| 3126 EXPECT_EQ(anchor1, document->focusedElement()); | |
| 3127 webViewImpl->advanceFocusInForm(WebFocusTypeBackward); | |
| 3128 EXPECT_EQ(anchor1, document->focusedElement()); | |
| 3129 | |
| 3130 // Navigation of elements which is not part of any forms. | |
| 3131 Element* textarea3 = document->getElementById("textarea3"); | |
| 3132 textarea3->focus(); | |
| 3133 textInputInfo = webViewImpl->textInputInfo(); | |
| 3134 // No Next/Previous element for elements outside form. | |
| 3135 EXPECT_EQ(defaultTextInputFlags, textInputInfo.flags); | |
| 3136 webViewImpl->advanceFocusInForm(WebFocusTypeForward); | |
| 3137 // No Next/Previous element to this element because it's not part of any | |
| 3138 // form. Hence focus won't change wrt NEXT/PREVIOUS. | |
| 3139 EXPECT_EQ(textarea3, document->focusedElement()); | |
| 3140 webViewImpl->advanceFocusInForm(WebFocusTypeBackward); | |
| 3141 EXPECT_EQ(textarea3, document->focusedElement()); | |
| 3142 | |
| 3143 // Navigation from an element which is part of a form but not an editable | |
| 3144 // element. | |
| 3145 Element* button2 = document->getElementById("button2"); | |
| 3146 button2->focus(); | |
| 3147 textInputInfo = webViewImpl->textInputInfo(); | |
| 3148 // No Next element for this element, due to last element outside the form. | |
| 3149 EXPECT_EQ(0, textInputInfo.flags); | |
| 3150 webViewImpl->advanceFocusInForm(WebFocusTypeForward); | |
| 3151 // No Next element to this element because it's not part of any form. | |
| 3152 // Hence focus won't change wrt NEXT. | |
| 3153 EXPECT_EQ(button2, document->focusedElement()); | |
| 3154 webViewImpl->advanceFocusInForm(WebFocusTypeBackward); | |
| 3155 // Since button is a form control element from form1, ensuring focus is set | |
| 3156 // at correct position. | |
| 3157 Element* textarea2 = document->getElementById("textarea2"); | |
| 3158 EXPECT_EQ(textarea2, document->focusedElement()); | |
| 3159 | |
| 3160 Element* contenteditable2 = document->getElementById("contenteditable2"); | |
| 3161 document->setFocusedElement(contenteditable2); | |
| 3162 textInputInfo = webViewImpl->textInputInfo(); | |
| 3163 // No Next/Previous element for elements outside form. | |
| 3164 EXPECT_EQ(0, textInputInfo.flags); | |
| 3165 webViewImpl->advanceFocusInForm(WebFocusTypeForward); | |
| 3166 // No Next/Previous element to this element because it's not part of any | |
| 3167 // form. Hence focus won't change wrt NEXT/PREVIOUS. | |
| 3168 EXPECT_EQ(contenteditable2, document->focusedElement()); | |
| 3169 webViewImpl->advanceFocusInForm(WebFocusTypeBackward); | |
| 3170 EXPECT_EQ(contenteditable2, document->focusedElement()); | |
| 3171 | |
| 3172 // Navigation of elements which is having invalid form attribute and hence | |
| 3173 // not part of any forms. | |
| 3174 Element* textarea4 = document->getElementById("textarea4"); | |
| 3175 textarea4->focus(); | |
| 3176 textInputInfo = webViewImpl->textInputInfo(); | |
| 3177 // No Next/Previous element for elements which is having invalid form | |
| 3178 // attribute. | |
| 3179 EXPECT_EQ(defaultTextInputFlags, textInputInfo.flags); | |
| 3180 webViewImpl->advanceFocusInForm(WebFocusTypeForward); | |
| 3181 // No Next/Previous element to this element because it's not part of any | |
| 3182 // form. Hence focus won't change wrt NEXT/PREVIOUS. | |
| 3183 EXPECT_EQ(textarea4, document->focusedElement()); | |
| 3184 webViewImpl->advanceFocusInForm(WebFocusTypeBackward); | |
| 3185 EXPECT_EQ(textarea4, document->focusedElement()); | |
| 3186 | |
| 3187 m_webViewHelper.reset(); | |
| 3188 } | |
| 3189 | |
| 3190 TEST_F(WebViewTest, MoveFocusToNextFocusableElementInFormWithNonEditableNonFormC
ontrolElements) | |
| 3191 { | |
| 3192 const std::string testFile = "advance_focus_in_form_with_key_event_listeners
.html"; | |
| 3193 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c
_str()), WebString::fromUTF8(testFile.c_str())); | |
| 3194 WebView* webViewImpl = m_webViewHelper.initializeAndLoad(m_baseURL + testFil
e, true, nullptr); | |
| 3195 webViewImpl->setInitialFocus(false); | |
| 3196 WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewImpl->mainFrame()); | |
| 3197 HTMLDocument* document = toHTMLDocument(frame->frame()->document()); | |
| 3198 const int defaultTextInputFlags = WebTextInputFlagAutocapitalizeSentences; | |
| 3199 | |
| 3200 struct FocusedElement { | |
| 3201 const char* elementId; | |
| 3202 int textInputFlags; | |
| 3203 } focusedElements[] = { | |
| 3204 {"textarea5", defaultTextInputFlags | WebTextInputFlagListeningToKeyboar
dEvents | WebTextInputFlagHaveNextFocusableElement}, | |
| 3205 {"input4", defaultTextInputFlags | WebTextInputFlagListeningToKeyboardEv
ents | WebTextInputFlagHaveNextFocusableElement | WebTextInputFlagHavePreviousFo
cusableElement}, | |
| 3206 {"contenteditable3", WebTextInputFlagListeningToKeyboardEvents | WebText
InputFlagHavePreviousFocusableElement}, | |
| 3207 }; | |
| 3208 | |
| 3209 // Forward Navigation in form2 with NEXT | |
| 3210 Element* textarea5 = document->getElementById("textarea5"); | |
| 3211 textarea5->focus(); | |
| 3212 Element* currentFocus = nullptr; | |
| 3213 WebTextInputInfo textInputInfo; | |
| 3214 for (size_t i = 0; i < WTF_ARRAY_LENGTH(focusedElements); ++i) { | |
| 3215 currentFocus = document->getElementById(focusedElements[i].elementId); | |
| 3216 EXPECT_EQ(currentFocus, document->focusedElement()); | |
| 3217 textInputInfo = webViewImpl->textInputInfo(); | |
| 3218 EXPECT_EQ(focusedElements[i].textInputFlags, textInputInfo.flags); | |
| 3219 webViewImpl->advanceFocusInForm(WebFocusTypeForward); | |
| 3220 } | |
| 3221 // Now focus will stay on previous focus itself, because it has no next | |
| 3222 // element. | |
| 3223 EXPECT_EQ(currentFocus, document->focusedElement()); | |
| 3224 | |
| 3225 // Backward Navigation in form1 with PREVIOUS | |
| 3226 for (size_t i = WTF_ARRAY_LENGTH(focusedElements); i-- > 0;) { | |
| 3227 currentFocus = document->getElementById(focusedElements[i].elementId); | |
| 3228 EXPECT_EQ(currentFocus, document->focusedElement()); | |
| 3229 textInputInfo = webViewImpl->textInputInfo(); | |
| 3230 EXPECT_EQ(focusedElements[i].textInputFlags, textInputInfo.flags); | |
| 3231 webViewImpl->advanceFocusInForm(WebFocusTypeBackward); | |
| 3232 } | |
| 3233 // Now focus will stay on previous focus itself, because it has no previous | |
| 3234 // element. | |
| 3235 EXPECT_EQ(currentFocus, document->focusedElement()); | |
| 3236 | |
| 3237 // Setting a non editable element as focus in form1, and ensuring editable | |
| 3238 // navigation is fine in forward and backward. | |
| 3239 Element* anchor2 = document->getElementById("anchor2"); | |
| 3240 anchor2->focus(); | |
| 3241 textInputInfo = webViewImpl->textInputInfo(); | |
| 3242 // No Next/Previous element for elements outside form. | |
| 3243 EXPECT_EQ(0, textInputInfo.flags); | |
| 3244 webViewImpl->advanceFocusInForm(WebFocusTypeForward); | |
| 3245 // No editable element after this inside the form, hence focus won't change. | |
| 3246 EXPECT_EQ(anchor2, document->focusedElement()); | |
| 3247 webViewImpl->advanceFocusInForm(WebFocusTypeBackward); | |
| 3248 // Since anchor is not a form control element, next/previous element will | |
| 3249 // be null, hence focus will stay same as it is. | |
| 3250 EXPECT_EQ(anchor2, document->focusedElement()); | |
| 3251 | |
| 3252 m_webViewHelper.reset(); | |
| 3253 } | |
| 3254 | |
| 3255 TEST_F(WebViewTest, MoveFocusToNextFocusableElementInFormWithTabIndexElements) | |
| 3256 { | |
| 3257 const std::string testFile = "advance_focus_in_form_with_tabindex_elements.h
tml"; | |
| 3258 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c
_str()), WebString::fromUTF8(testFile.c_str())); | |
| 3259 WebView* webViewImpl = m_webViewHelper.initializeAndLoad(m_baseURL + testFil
e, true, nullptr); | |
| 3260 webViewImpl->setInitialFocus(false); | |
| 3261 WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewImpl->mainFrame()); | |
| 3262 HTMLDocument* document = toHTMLDocument(frame->frame()->document()); | |
| 3263 const int defaultTextInputFlags = WebTextInputFlagAutocapitalizeSentences; | |
| 3264 | |
| 3265 struct FocusedElement { | |
| 3266 const char* elementId; | |
| 3267 int textInputFlags; | |
| 3268 } focusedElements[] = { | |
| 3269 {"textarea6", defaultTextInputFlags | WebTextInputFlagHaveNextFocusableE
lement}, | |
| 3270 {"input5", defaultTextInputFlags | WebTextInputFlagHaveNextFocusableElem
ent | WebTextInputFlagHavePreviousFocusableElement}, | |
| 3271 {"contenteditable4", WebTextInputFlagHaveNextFocusableElement | WebTextI
nputFlagHavePreviousFocusableElement}, | |
| 3272 {"input6", defaultTextInputFlags | WebTextInputFlagHavePreviousFocusable
Element}, | |
| 3273 }; | |
| 3274 | |
| 3275 // Forward Navigation in form with NEXT which has tabindex attribute | |
| 3276 // which differs visual order. | |
| 3277 Element* textarea6 = document->getElementById("textarea6"); | |
| 3278 textarea6->focus(); | |
| 3279 Element* currentFocus = nullptr; | |
| 3280 WebTextInputInfo textInputInfo; | |
| 3281 for (size_t i = 0; i < WTF_ARRAY_LENGTH(focusedElements); ++i) { | |
| 3282 currentFocus = document->getElementById(focusedElements[i].elementId); | |
| 3283 EXPECT_EQ(currentFocus, document->focusedElement()); | |
| 3284 textInputInfo = webViewImpl->textInputInfo(); | |
| 3285 EXPECT_EQ(focusedElements[i].textInputFlags, textInputInfo.flags); | |
| 3286 webViewImpl->advanceFocusInForm(WebFocusTypeForward); | |
| 3287 } | |
| 3288 // No next editable element which is focusable with proper tab index, hence | |
| 3289 // staying on previous focus. | |
| 3290 EXPECT_EQ(currentFocus, document->focusedElement()); | |
| 3291 | |
| 3292 // Backward Navigation in form with PREVIOUS which has tabindex attribute | |
| 3293 // which differs visual order. | |
| 3294 for (size_t i = WTF_ARRAY_LENGTH(focusedElements); i-- > 0;) { | |
| 3295 currentFocus = document->getElementById(focusedElements[i].elementId); | |
| 3296 EXPECT_EQ(currentFocus, document->focusedElement()); | |
| 3297 textInputInfo = webViewImpl->textInputInfo(); | |
| 3298 EXPECT_EQ(focusedElements[i].textInputFlags, textInputInfo.flags); | |
| 3299 webViewImpl->advanceFocusInForm(WebFocusTypeBackward); | |
| 3300 } | |
| 3301 // Now focus will stay on previous focus itself, because it has no previous | |
| 3302 // element. | |
| 3303 EXPECT_EQ(currentFocus, document->focusedElement()); | |
| 3304 | |
| 3305 // Setting an element which has invalid tabindex and ensuring it is not | |
| 3306 // modifying further navigation. | |
| 3307 Element* contenteditable5 = document->getElementById("contenteditable5"); | |
| 3308 contenteditable5->focus(); | |
| 3309 webViewImpl->advanceFocusInForm(WebFocusTypeForward); | |
| 3310 Element* input6 = document->getElementById("input6"); | |
| 3311 EXPECT_EQ(input6, document->focusedElement()); | |
| 3312 contenteditable5->focus(); | |
| 3313 webViewImpl->advanceFocusInForm(WebFocusTypeBackward); | |
| 3314 EXPECT_EQ(textarea6, document->focusedElement()); | |
| 3315 | |
| 3316 m_webViewHelper.reset(); | |
| 3317 } | |
| 3318 | |
| 3319 TEST_F(WebViewTest, MoveFocusToNextFocusableElementInFormWithDisabledAndReadonly
Elements) | |
| 3320 { | |
| 3321 const std::string testFile = "advance_focus_in_form_with_disabled_and_readon
ly_elements.html"; | |
| 3322 URLTestHelpers::registerMockedURLFromBaseURL(WebString::fromUTF8(m_baseURL.c
_str()), WebString::fromUTF8(testFile.c_str())); | |
| 3323 WebView* webViewImpl = m_webViewHelper.initializeAndLoad(m_baseURL + testFil
e, true, nullptr); | |
| 3324 webViewImpl->setInitialFocus(false); | |
| 3325 WebLocalFrameImpl* frame = toWebLocalFrameImpl(webViewImpl->mainFrame()); | |
| 3326 HTMLDocument* document = toHTMLDocument(frame->frame()->document()); | |
| 3327 | |
| 3328 struct FocusedElement { | |
| 3329 const char* elementId; | |
| 3330 int textInputFlags; | |
| 3331 } focusedElements[] = { | |
| 3332 {"contenteditable6", WebTextInputFlagHaveNextFocusableElement}, | |
| 3333 {"contenteditable7", WebTextInputFlagHavePreviousFocusableElement}, | |
| 3334 }; | |
| 3335 // Forward Navigation in form with NEXT which has has disabled/enabled | |
| 3336 // elements which will gets skipped during navigation. | |
| 3337 Element* contenteditable6 = document->getElementById("contenteditable6"); | |
| 3338 contenteditable6->focus(); | |
| 3339 Element* currentFocus = nullptr; | |
| 3340 WebTextInputInfo textInputInfo; | |
| 3341 for (size_t i = 0; i < WTF_ARRAY_LENGTH(focusedElements); ++i) { | |
| 3342 currentFocus = document->getElementById(focusedElements[i].elementId); | |
| 3343 EXPECT_EQ(currentFocus, document->focusedElement()); | |
| 3344 textInputInfo = webViewImpl->textInputInfo(); | |
| 3345 EXPECT_EQ(focusedElements[i].textInputFlags, textInputInfo.flags); | |
| 3346 webViewImpl->advanceFocusInForm(WebFocusTypeForward); | |
| 3347 } | |
| 3348 // No next editable element which is focusable, hence staying on previous | |
| 3349 // focus. | |
| 3350 EXPECT_EQ(currentFocus, document->focusedElement()); | |
| 3351 | |
| 3352 // Backward Navigation in form with PREVIOUS which has has | |
| 3353 // disabled/enabled elements which will gets skipped during navigation. | |
| 3354 for (size_t i = WTF_ARRAY_LENGTH(focusedElements); i-- > 0;) { | |
| 3355 currentFocus = document->getElementById(focusedElements[i].elementId); | |
| 3356 EXPECT_EQ(currentFocus, document->focusedElement()); | |
| 3357 textInputInfo = webViewImpl->textInputInfo(); | |
| 3358 EXPECT_EQ(focusedElements[i].textInputFlags, textInputInfo.flags); | |
| 3359 webViewImpl->advanceFocusInForm(WebFocusTypeBackward); | |
| 3360 } | |
| 3361 // Now focus will stay on previous focus itself, because it has no previous | |
| 3362 // element. | |
| 3363 EXPECT_EQ(currentFocus, document->focusedElement()); | |
| 3364 | |
| 3365 m_webViewHelper.reset(); | |
| 3366 } | |
| 3367 | |
| 3368 } // namespace blink | 3054 } // namespace blink |
| OLD | NEW |