/* GNU LESSER GENERAL PUBLIC LICENSE Copyright (C) 2006 The Lobo Project This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Contact info: lobochief@users.sourceforge.net */ /* * Created on Nov 19, 2005 */ package org.lobobrowser.html.domimpl; import java.util.ArrayList; import org.eclipse.jdt.annotation.NonNull; import org.lobobrowser.html.js.Executor; import org.lobobrowser.html.js.Window; import org.lobobrowser.html.style.ImageRenderState; import org.lobobrowser.html.style.RenderState; import org.lobobrowser.ua.ImageResponse; import org.lobobrowser.ua.ImageResponse.State; import org.mozilla.javascript.Function; import org.w3c.dom.UserDataHandler; import org.w3c.dom.html.HTMLImageElement; public class HTMLImageElementImpl extends HTMLAbstractUIElement implements HTMLImageElement { public HTMLImageElementImpl() { super("IMG"); } public HTMLImageElementImpl(final String name) { super(name); } public String getName() { return this.getAttribute("name"); } public void setName(final String name) { this.setAttribute("name", name); } public String getAlign() { return this.getAttribute("align"); } public void setAlign(final String align) { this.setAttribute("align", align); } public String getAlt() { return this.getAttribute("alt"); } public void setAlt(final String alt) { this.setAttribute("alt", alt); } public String getBorder() { return this.getAttribute("border"); } public void setBorder(final String border) { this.setAttribute("border", border); } /* public int getHeight() { final UINode r = this.uiNode; return r == null ? 0 : r.getBounds().height; } public void setHeight(final int height) { this.setAttribute("height", String.valueOf(height)); } public int getHspace() { return this.getAttributeAsInt("hspace", 0); } public void setHspace(final int hspace) { this.setAttribute("hspace", String.valueOf("hspace")); } */ public String getHeight() { final UINode r = this.uiNode; final int height = r == null ? 0 : r.getBounds().height; return String.valueOf(height); } public void setHeight(final String height) { this.setAttribute("height", height); } public String getHspace() { return this.getAttribute("hspace"); } public void setHspace(final String hspace) { this.setAttribute("hspace", hspace); } public boolean getIsMap() { return this.getAttributeAsBoolean("isMap"); } public void setIsMap(final boolean isMap) { this.setAttribute("isMap", isMap ? "isMap" : null); } public String getLongDesc() { return this.getAttribute("longDesc"); } public void setLongDesc(final String longDesc) { this.setAttribute("longDesc", longDesc); } public String getSrc() { return this.getAttribute("src"); } /** * Sets the image URI and starts to load the image. Note that an * HtmlRendererContext should be available to the HTML document for images to * be loaded. */ public void setSrc(final String src) { this.setAttribute("src", src); } public String getUseMap() { return this.getAttribute("useMap"); } public void setUseMap(final String useMap) { this.setAttribute("useMap", useMap); } /* public int getVspace() { return this.getAttributeAsInt("vspace", 0); } public void setVspace(final int vspace) { this.setAttribute("vspace", String.valueOf(vspace)); } */ public String getVspace() { return this.getAttribute("vspace"); } public void setVspace(final String vspace) { this.setAttribute("vspace", vspace); } /* public int getWidth() { final UINode r = this.uiNode; return r == null ? 0 : r.getBounds().width; } public void setWidth(final int width) { this.setAttribute("width", String.valueOf(width)); }*/ public String getWidth() { final UINode r = this.uiNode; final int width = r == null ? 0 : r.getBounds().width; return String.valueOf(width); } public void setWidth(final String width) { this.setAttribute("width", width); } @Override protected void handleAttributeChanged(final String name, final String oldValue, final String newValue) { super.handleAttributeChanged(name, oldValue, newValue); if ("src".equals(name)) { ((HTMLDocumentImpl) document).addJob(() -> loadImage(getSrc()), false); } } private Function onload; public Function getOnload() { return this.getEventFunction(this.onload, "onload"); } public void setOnload(final Function onload) { this.onload = onload; } private @NonNull ImageResponse imageResponse = new ImageResponse(); private String imageSrc; private void loadImage(final String src) { final HTMLDocumentImpl document = (HTMLDocumentImpl) this.document; if (document != null) { synchronized (this.listeners) { this.imageSrc = src; this.imageResponse = new ImageResponse(); } if (src != null) { document.loadImage(src, new LocalImageListener(src)); } else { document.markJobsFinished(1, false); } } } @Override public Object setUserData(final String key, final Object data, final UserDataHandler handler) { if (org.lobobrowser.html.parser.HtmlParser.MODIFYING_KEY.equals(key) && (data != Boolean.TRUE)) { ((HTMLDocumentImpl) document).addJob(() -> loadImage(getSrc()), false); // this.loadImage(getSrc()); } return super.setUserData(key, data, handler); } private final ArrayList<ImageListener> listeners = new ArrayList<>(1); /** * Adds a listener of image loading events. The listener gets called right * away if there's already an image. * * @param listener */ public void addImageListener(final ImageListener listener) { final ArrayList<ImageListener> l = this.listeners; ImageResponse currentImageResponse; synchronized (l) { currentImageResponse = this.imageResponse; l.add(listener); } if (currentImageResponse.state != State.loading) { // Call listener right away if there's already an // image; holding no locks. listener.imageLoaded(new ImageEvent(this, currentImageResponse)); // Should not call onload handler here. That's taken // care of otherwise. } } public void removeImageListener(final ImageListener listener) { final ArrayList<ImageListener> l = this.listeners; synchronized (l) { l.remove(l); } } private void dispatchEvent(final String expectedImgSrc, final ImageEvent event) { final ArrayList<ImageListener> l = this.listeners; ImageListener[] listenerArray; synchronized (l) { if (!expectedImgSrc.equals(this.imageSrc)) { return; } this.imageResponse = event.imageResponse; // Get array of listeners while holding lock. listenerArray = l.toArray(ImageListener.EMPTY_ARRAY); } final int llength = listenerArray.length; for (int i = 0; i < llength; i++) { // Inform listener, holding no lock. listenerArray[i].imageLoaded(event); } final Function onload = this.getOnload(); if (onload != null) { // TODO: onload event object? final Window window = ((HTMLDocumentImpl) document).getWindow(); Executor.executeFunction(HTMLImageElementImpl.this, onload, null, window.getContextFactory()); } } @Override protected @NonNull RenderState createRenderState(final RenderState prevRenderState) { return new ImageRenderState(prevRenderState, this); } private class LocalImageListener implements ImageListener { private final String expectedImgSrc; public LocalImageListener(final String imgSrc) { this.expectedImgSrc = imgSrc; } public void imageLoaded(final ImageEvent event) { dispatchEvent(this.expectedImgSrc, event); if (document instanceof HTMLDocumentImpl) { final HTMLDocumentImpl htmlDocumentImpl = (HTMLDocumentImpl) document; htmlDocumentImpl.markJobsFinished(1, false); } } public void imageAborted() { if (document instanceof HTMLDocumentImpl) { final HTMLDocumentImpl htmlDocumentImpl = (HTMLDocumentImpl) document; htmlDocumentImpl.markJobsFinished(1, false); } } } public String getLowSrc() { // TODO return null; } public void setLowSrc(final String lowSrc) { // TODO } }