1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.htmlunit;
16
17 import static org.htmlunit.BrowserVersionFeatures.JS_WINDOW_COMPUTED_STYLE_PSEUDO_ACCEPT_WITHOUT_COLON;
18 import static org.htmlunit.BrowserVersionFeatures.JS_WINDOW_OUTER_INNER_HEIGHT_DIFF_138;
19 import static org.htmlunit.BrowserVersionFeatures.JS_WINDOW_OUTER_INNER_HEIGHT_DIFF_147;
20 import static org.htmlunit.BrowserVersionFeatures.JS_WINDOW_OUTER_INNER_HEIGHT_DIFF_94;
21
22 import java.io.IOException;
23 import java.io.ObjectInputStream;
24 import java.io.ObjectOutputStream;
25 import java.util.ArrayList;
26 import java.util.List;
27
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30 import org.htmlunit.css.ComputedCssStyleDeclaration;
31 import org.htmlunit.css.CssStyleSheet;
32 import org.htmlunit.css.ElementCssStyleDeclaration;
33 import org.htmlunit.html.DomElement;
34 import org.htmlunit.html.HtmlPage;
35 import org.htmlunit.javascript.HtmlUnitScriptable;
36 import org.htmlunit.javascript.background.BackgroundJavaScriptFactory;
37 import org.htmlunit.javascript.background.JavaScriptJobManager;
38 import org.htmlunit.javascript.host.Window;
39 import org.w3c.dom.Document;
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 public abstract class WebWindowImpl implements WebWindow {
55
56 private static final Log LOG = LogFactory.getLog(WebWindowImpl.class);
57
58 private final WebClient webClient_;
59 private final Screen screen_;
60 private Page enclosedPage_;
61 private transient HtmlUnitScriptable scriptObject_;
62 private JavaScriptJobManager jobManager_;
63 private final List<WebWindowImpl> childWindows_ = new ArrayList<>();
64 private String name_ = "";
65 private final History history_ = new History(this);
66 private boolean closed_;
67
68 private int innerHeight_;
69 private int outerHeight_;
70 private int innerWidth_;
71 private int outerWidth_;
72
73
74
75
76
77
78 public WebWindowImpl(final WebClient webClient) {
79 WebAssert.notNull("webClient", webClient);
80 webClient_ = webClient;
81 jobManager_ = BackgroundJavaScriptFactory.theFactory().createJavaScriptJobManager(this);
82
83 screen_ = new Screen(webClient);
84
85 innerHeight_ = 605;
86 innerWidth_ = 1256;
87 if (webClient.getBrowserVersion().hasFeature(JS_WINDOW_OUTER_INNER_HEIGHT_DIFF_94)) {
88 outerHeight_ = innerHeight_ + 94;
89 outerWidth_ = innerWidth_ + 16;
90 }
91 else if (webClient.getBrowserVersion().hasFeature(JS_WINDOW_OUTER_INNER_HEIGHT_DIFF_138)) {
92 outerHeight_ = innerHeight_ + 138;
93 outerWidth_ = innerWidth_ + 24;
94 }
95 else if (webClient.getBrowserVersion().hasFeature(JS_WINDOW_OUTER_INNER_HEIGHT_DIFF_147)) {
96 outerHeight_ = innerHeight_ + 147;
97 outerWidth_ = innerWidth_ + 16;
98 }
99 else {
100 outerHeight_ = innerHeight_ + 115;
101 outerWidth_ = innerWidth_ + 14;
102 }
103 }
104
105
106
107
108 protected void performRegistration() {
109 webClient_.registerWebWindow(this);
110 }
111
112
113
114
115 @Override
116 public WebClient getWebClient() {
117 return webClient_;
118 }
119
120
121
122
123 @Override
124 public Screen getScreen() {
125 return screen_;
126 }
127
128
129
130
131 @Override
132 public Page getEnclosedPage() {
133 return enclosedPage_;
134 }
135
136
137
138
139 @Override
140 public void setEnclosedPage(final Page page) {
141 if (LOG.isDebugEnabled()) {
142 LOG.debug("setEnclosedPage: " + page);
143 }
144 if (page == enclosedPage_) {
145 return;
146 }
147 destroyChildren();
148
149 if (isJavaScriptInitializationNeeded(page)) {
150 webClient_.initialize(this, page);
151 }
152 if (webClient_.isJavaScriptEngineEnabled()) {
153 final Window window = getScriptableObject();
154 window.initialize(page);
155 }
156
157
158
159 enclosedPage_ = page;
160 history_.addPage(page);
161 }
162
163
164
165
166
167
168 protected abstract boolean isJavaScriptInitializationNeeded(Page page);
169
170
171
172
173 @Override
174 public <T extends HtmlUnitScriptable> void setScriptableObject(final T scriptObject) {
175 scriptObject_ = scriptObject;
176 }
177
178
179
180
181 @Override
182 @SuppressWarnings("unchecked")
183 public <T> T getScriptableObject() {
184 return (T) scriptObject_;
185 }
186
187
188
189
190 @Override
191 public JavaScriptJobManager getJobManager() {
192 return jobManager_;
193 }
194
195
196
197
198
199
200
201
202 public void setJobManager(final JavaScriptJobManager jobManager) {
203 jobManager_ = jobManager;
204 }
205
206
207
208
209
210
211
212
213 public void addChildWindow(final WebWindowImpl child) {
214 synchronized (childWindows_) {
215 childWindows_.add(child);
216 }
217 }
218
219
220
221
222 protected void destroyChildren() {
223 LOG.debug("destroyChildren");
224 getJobManager().removeAllJobs();
225
226
227 while (!childWindows_.isEmpty()) {
228 final WebWindowImpl window = childWindows_.get(0);
229 removeChildWindow(window);
230 }
231 }
232
233
234
235
236
237
238
239 public void removeChildWindow(final WebWindowImpl window) {
240 if (LOG.isDebugEnabled()) {
241 LOG.debug("closing child window: " + window);
242 }
243 window.setClosed();
244 window.getJobManager().shutdown();
245 final Page page = window.getEnclosedPage();
246 if (page != null) {
247 page.cleanUp();
248 }
249 window.destroyChildren();
250
251 synchronized (childWindows_) {
252 childWindows_.remove(window);
253 }
254 webClient_.deregisterWebWindow(window);
255 }
256
257
258
259
260 @Override
261 public String getName() {
262 return name_;
263 }
264
265
266
267
268 @Override
269 public void setName(final String name) {
270 name_ = name;
271 }
272
273
274
275
276
277 @Override
278 public History getHistory() {
279 return history_;
280 }
281
282
283
284
285 @Override
286 public boolean isClosed() {
287 return closed_;
288 }
289
290
291
292
293 protected void setClosed() {
294 closed_ = true;
295 }
296
297
298
299
300 @Override
301 public int getInnerWidth() {
302 return innerWidth_;
303 }
304
305
306
307
308 @Override
309 public void setInnerWidth(final int innerWidth) {
310 innerWidth_ = innerWidth;
311 }
312
313
314
315
316 @Override
317 public int getOuterWidth() {
318 return outerWidth_;
319 }
320
321
322
323
324 @Override
325 public void setOuterWidth(final int outerWidth) {
326 outerWidth_ = outerWidth;
327 }
328
329
330
331
332 @Override
333 public int getInnerHeight() {
334 return innerHeight_;
335 }
336
337
338
339
340 @Override
341 public void setInnerHeight(final int innerHeight) {
342 innerHeight_ = innerHeight;
343 }
344
345
346
347
348 @Override
349 public int getOuterHeight() {
350 return outerHeight_;
351 }
352
353
354
355
356 @Override
357 public void setOuterHeight(final int outerHeight) {
358 outerHeight_ = outerHeight;
359 }
360
361 private void writeObject(final ObjectOutputStream oos) throws IOException {
362 oos.defaultWriteObject();
363 oos.writeObject(scriptObject_);
364 }
365
366 private void readObject(final ObjectInputStream ois) throws ClassNotFoundException, IOException {
367 ois.defaultReadObject();
368 scriptObject_ = (HtmlUnitScriptable) ois.readObject();
369 }
370
371
372
373
374 @Override
375 public ComputedCssStyleDeclaration getComputedStyle(final DomElement element, final String pseudoElement) {
376 String normalizedPseudo = pseudoElement;
377 if (normalizedPseudo != null) {
378 if (normalizedPseudo.startsWith("::")) {
379 normalizedPseudo = normalizedPseudo.substring(1);
380 }
381 else if (getWebClient().getBrowserVersion().hasFeature(JS_WINDOW_COMPUTED_STYLE_PSEUDO_ACCEPT_WITHOUT_COLON)
382 && normalizedPseudo.length() > 0 && normalizedPseudo.charAt(0) != ':') {
383 normalizedPseudo = ":" + normalizedPseudo;
384 }
385 }
386
387 final SgmlPage sgmlPage = element.getPage();
388 if (sgmlPage instanceof HtmlPage) {
389 final ComputedCssStyleDeclaration styleFromCache =
390 ((HtmlPage) sgmlPage).getStyleFromCache(element, normalizedPseudo);
391 if (styleFromCache != null) {
392 return styleFromCache;
393 }
394 }
395
396 final ComputedCssStyleDeclaration computedsStyleDeclaration =
397 new ComputedCssStyleDeclaration(new ElementCssStyleDeclaration(element));
398
399 final Document ownerDocument = element.getOwnerDocument();
400 if (ownerDocument instanceof HtmlPage) {
401 final HtmlPage htmlPage = (HtmlPage) ownerDocument;
402
403 final WebClient webClient = getWebClient();
404
405 if (webClient.getOptions().isCssEnabled()) {
406 final boolean trace = LOG.isTraceEnabled();
407 for (final CssStyleSheet cssStyleSheet : htmlPage.getStyleSheets()) {
408 if (cssStyleSheet != null
409 && cssStyleSheet.isEnabled()
410 && cssStyleSheet.isActive()) {
411 if (trace) {
412 LOG.trace("modifyIfNecessary: " + cssStyleSheet
413 + ", " + computedsStyleDeclaration + ", " + element);
414 }
415 cssStyleSheet.modifyIfNecessary(computedsStyleDeclaration, element, normalizedPseudo);
416 }
417 }
418 }
419
420 ((HtmlPage) element.getPage()).putStyleIntoCache(element, normalizedPseudo, computedsStyleDeclaration);
421 }
422
423 return computedsStyleDeclaration;
424 }
425 }