/*
 * Copyright (C) 2006, 2007 Apple Inc.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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. 
 */

cpp_quote("/*")
cpp_quote(" * Copyright (C) 2006, 2007 Apple Inc.  All rights reserved.")
cpp_quote(" *")
cpp_quote(" * Redistribution and use in source and binary forms, with or without")
cpp_quote(" * modification, are permitted provided that the following conditions")
cpp_quote(" * are met:")
cpp_quote(" * 1. Redistributions of source code must retain the above copyright")
cpp_quote(" *    notice, this list of conditions and the following disclaimer.")
cpp_quote(" * 2. Redistributions in binary form must reproduce the above copyright")
cpp_quote(" *    notice, this list of conditions and the following disclaimer in the")
cpp_quote(" *    documentation and/or other materials provided with the distribution.")
cpp_quote(" *")
cpp_quote(" * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY")
cpp_quote(" * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE")
cpp_quote(" * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR")
cpp_quote(" * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR")
cpp_quote(" * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,")
cpp_quote(" * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,")
cpp_quote(" * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR")
cpp_quote(" * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY")
cpp_quote(" * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT")
cpp_quote(" * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE")
cpp_quote(" * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ")
cpp_quote(" */")

import "oaidl.idl";
import "ocidl.idl";
import "DOMCore.idl";

typedef struct WebFontDescription WebFontDescription;

[
    object,
    oleautomation,
    uuid(7FF28EC8-6DA1-498d-9A43-7E67C2D3128F),
    pointer_default(unique)
]
interface IDOMElementPrivate : IUnknown
{
    [local] HRESULT coreElement(void** element);
    HRESULT isEqual([in] IDOMElement* other, [out, retval] BOOL* result);
    HRESULT isFocused([out, retval] BOOL* result);
    HRESULT innerText([out, retval] BSTR* result);
    [local] HRESULT font(WebFontDescription* webFontDescription);
}

/*
    All the methods in this category are used by Safari forms autofill and should not be used for any other purpose.
    They are stopgap measures until we finish transitioning form controls to not use NSView. Each one should become
    replaceable by public DOM API, and when that happens Safari will switch to implementations using that public API,
    and these will be deleted.

    @interface DOMHTMLInputElement(FormsAutoFillTransition)
*/
[
    object,
    oleautomation,
    uuid(2DF339BC-B48E-4d35-B93A-299756ED0B4B),
    pointer_default(unique)
]
interface IFormsAutoFillTransition : IUnknown
{
    /*
        - (BOOL)_isTextField;
    */
    HRESULT isTextField([out, retval] BOOL* result);

    /*
        - (NSRect)_rectOnScreen; // bounding box of the text field, in screen coordinates
    */
    HRESULT rectOnScreen([out, retval] LPRECT rect);

    /*
        - (void)_replaceCharactersInRange:(NSRange)targetRange withString:(NSString *)replacementString selectingFromIndex:(int)index;
    */
    HRESULT replaceCharactersInRange([in] int startTarget, [in] int endTarget, [in] BSTR replacementString, [in] int index);

    /*
        - (NSRange)_selectedRange;
    */
    HRESULT selectedRange([out] int* start, [out] int* end);

    /*
        - (void)_setAutofilled:(BOOL)filled;
    */
    HRESULT setAutofilled([in] BOOL filled);
}

/*
    // These changes are necessary to detect whether a form input was modified by a user
    // or javascript
    @interface DOMHTMLInputElement (FormPromptAdditions)

    @interface DOMHTMLTextAreaElement (FormPromptAdditions)
*/
[
    object,
    oleautomation,
    uuid(C8C5F0CD-07B0-4a32-BFA8-AE465E80DD3C),
    pointer_default(unique)
]
interface IFormPromptAdditions : IUnknown
{
    /*
        - (BOOL)_isUserEdited;
    */
    HRESULT isUserEdited([out, retval] BOOL* result);
}

/*
    All the methods in this category are used by Safari forms autofill and should not be used for any other purpose.
    They are stopgap measures until we finish transitioning form controls to not use NSView. Each one should become
    replaceable by public DOM API, and when that happens Safari will switch to implementations using that public API,
    and these will be deleted.

    @interface DOMHTMLSelectElement(FormsAutoFillTransition)
*/
[
    object,
    oleautomation,
    uuid(6959F712-1563-4661-8D8C-F4C739C55839),
    pointer_default(unique)
]
interface IFormsAutoFillTransitionSelect : IUnknown
{
    /*
        - (void)_activateItemAtIndex:(int)index;
    */
    HRESULT activateItemAtIndex([in] int index);
}
