d80f2a6eb5fb932d7eaa4a8e217a25163df7461b
[WebKit-https.git] / Source / WebKit2 / WebProcess / WebCoreSupport / WebGraphicsLayer.cpp
1 /*
2  Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
3
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Library General Public
6  License as published by the Free Software Foundation; either
7  version 2 of the License, or (at your option) any later version.
8
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  Library General Public License for more details.
13
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB.  If not, write to
16  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  Boston, MA 02110-1301, USA.
18  */
19
20 #include "config.h"
21
22 #if USE(UI_SIDE_COMPOSITING)
23 #include "WebGraphicsLayer.h"
24
25 #include "BackingStore.h"
26 #include "FloatQuad.h"
27 #include "Frame.h"
28 #include "FrameView.h"
29 #include "GraphicsContext.h"
30 #include "GraphicsLayer.h"
31 #include "LayerTreeHostProxyMessages.h"
32 #include "Page.h"
33 #include "TiledBackingStoreRemoteTile.h"
34 #include "WebPage.h"
35 #include <wtf/CurrentTime.h>
36 #include <wtf/HashMap.h>
37 #include <wtf/text/CString.h>
38
39 using namespace WebKit;
40
41 namespace WebCore {
42
43 static HashMap<WebLayerID, WebGraphicsLayer*>& layerByIDMap()
44 {
45     static HashMap<WebLayerID, WebGraphicsLayer*> globalMap;
46     return globalMap;
47 }
48
49 WebGraphicsLayer* WebGraphicsLayer::layerByID(WebKit::WebLayerID id)
50 {
51     HashMap<WebLayerID, WebGraphicsLayer*>& table = layerByIDMap();
52     HashMap<WebLayerID, WebGraphicsLayer*>::iterator it = table.find(id);
53     if (it == table.end())
54         return 0;
55     return it->second;
56 }
57
58 static WebLayerID toWebLayerID(GraphicsLayer* layer)
59 {
60     return layer ? toWebGraphicsLayer(layer)->id() : 0;
61 }
62
63 void WebGraphicsLayer::didChangeLayerState()
64 {
65     m_shouldSyncLayerState = true;
66     if (client())
67         client()->notifySyncRequired(this);
68 }
69
70 void WebGraphicsLayer::didChangeChildren()
71 {
72     m_shouldSyncChildren = true;
73     if (client())
74         client()->notifySyncRequired(this);
75 }
76
77 void WebGraphicsLayer::setShouldUpdateVisibleRect()
78 {
79     if (!transform().isAffine())
80         return;
81
82     m_shouldUpdateVisibleRect = true;
83     for (size_t i = 0; i < children().size(); ++i)
84         toWebGraphicsLayer(children()[i])->setShouldUpdateVisibleRect();
85     if (replicaLayer())
86         toWebGraphicsLayer(replicaLayer())->setShouldUpdateVisibleRect();
87 }
88
89 void WebGraphicsLayer::didChangeGeometry()
90 {
91     didChangeLayerState();
92     setShouldUpdateVisibleRect();
93 }
94
95 WebGraphicsLayer::WebGraphicsLayer(GraphicsLayerClient* client)
96     : GraphicsLayer(client)
97     , m_maskTarget(0)
98     , m_inUpdateMode(false)
99     , m_fixedToViewport(false)
100     , m_shouldUpdateVisibleRect(true)
101     , m_shouldSyncLayerState(true)
102     , m_shouldSyncChildren(true)
103     , m_webGraphicsLayerClient(0)
104     , m_contentsScale(1)
105 {
106     static WebLayerID nextLayerID = 1;
107     m_id = nextLayerID++;
108     layerByIDMap().add(id(), this);
109 }
110
111 WebGraphicsLayer::~WebGraphicsLayer()
112 {
113     layerByIDMap().remove(id());
114
115     if (m_webGraphicsLayerClient) {
116         purgeBackingStores();
117         m_webGraphicsLayerClient->detachLayer(this);
118     }
119     willBeDestroyed();
120 }
121
122 void WebGraphicsLayer::willBeDestroyed()
123 {
124     GraphicsLayer::willBeDestroyed();
125 }
126
127 bool WebGraphicsLayer::setChildren(const Vector<GraphicsLayer*>& children)
128 {
129     bool ok = GraphicsLayer::setChildren(children);
130     if (!ok)
131         return false;
132     for (int i = 0; i < children.size(); ++i) {
133         WebGraphicsLayer* child = toWebGraphicsLayer(children[i]);
134         child->setWebGraphicsLayerClient(m_webGraphicsLayerClient);
135         child->didChangeLayerState();
136     }
137     didChangeChildren();
138     return true;
139 }
140
141 void WebGraphicsLayer::addChild(GraphicsLayer* layer)
142 {
143     GraphicsLayer::addChild(layer);
144     toWebGraphicsLayer(layer)->setWebGraphicsLayerClient(m_webGraphicsLayerClient);
145     toWebGraphicsLayer(layer)->didChangeLayerState();
146     didChangeChildren();
147 }
148
149 void WebGraphicsLayer::addChildAtIndex(GraphicsLayer* layer, int index)
150 {
151     GraphicsLayer::addChildAtIndex(layer, index);
152     toWebGraphicsLayer(layer)->setWebGraphicsLayerClient(m_webGraphicsLayerClient);
153     toWebGraphicsLayer(layer)->didChangeLayerState();
154     didChangeChildren();
155 }
156
157 void WebGraphicsLayer::addChildAbove(GraphicsLayer* layer, GraphicsLayer* sibling)
158 {
159     GraphicsLayer::addChildAbove(layer, sibling);
160     toWebGraphicsLayer(layer)->setWebGraphicsLayerClient(m_webGraphicsLayerClient);
161     toWebGraphicsLayer(layer)->didChangeLayerState();
162     didChangeChildren();
163 }
164
165 void WebGraphicsLayer::addChildBelow(GraphicsLayer* layer, GraphicsLayer* sibling)
166 {
167     GraphicsLayer::addChildBelow(layer, sibling);
168     toWebGraphicsLayer(layer)->setWebGraphicsLayerClient(m_webGraphicsLayerClient);
169     toWebGraphicsLayer(layer)->didChangeLayerState();
170     didChangeChildren();
171 }
172
173 bool WebGraphicsLayer::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
174 {
175     bool ok = GraphicsLayer::replaceChild(oldChild, newChild);
176     if (!ok)
177         return false;
178     didChangeChildren();
179     toWebGraphicsLayer(oldChild)->didChangeLayerState();
180     toWebGraphicsLayer(newChild)->setWebGraphicsLayerClient(m_webGraphicsLayerClient);
181     toWebGraphicsLayer(newChild)->didChangeLayerState();
182     return true;
183 }
184
185 void WebGraphicsLayer::removeFromParent()
186 {
187     if (WebGraphicsLayer* parentLayer = toWebGraphicsLayer(parent()))
188         parentLayer->didChangeChildren();
189     GraphicsLayer::removeFromParent();
190
191     didChangeLayerState();
192 }
193
194 void WebGraphicsLayer::setPosition(const FloatPoint& p)
195 {
196     if (position() == p)
197         return;
198
199     GraphicsLayer::setPosition(p);
200     didChangeGeometry();
201 }
202
203 void WebGraphicsLayer::setAnchorPoint(const FloatPoint3D& p)
204 {
205     if (anchorPoint() == p)
206         return;
207
208     GraphicsLayer::setAnchorPoint(p);
209     didChangeGeometry();
210 }
211
212 void WebGraphicsLayer::setSize(const FloatSize& size)
213 {
214     if (this->size() == size)
215         return;
216
217     GraphicsLayer::setSize(size);
218     setNeedsDisplay();
219     if (maskLayer())
220         maskLayer()->setSize(size);
221     didChangeGeometry();
222 }
223
224 void WebGraphicsLayer::setTransform(const TransformationMatrix& t)
225 {
226     if (transform() == t)
227         return;
228
229     GraphicsLayer::setTransform(t);
230     didChangeGeometry();
231 }
232
233 void WebGraphicsLayer::setChildrenTransform(const TransformationMatrix& t)
234 {
235     if (childrenTransform() == t)
236         return;
237
238     GraphicsLayer::setChildrenTransform(t);
239     didChangeGeometry();
240 }
241
242 void WebGraphicsLayer::setPreserves3D(bool b)
243 {
244     if (preserves3D() == b)
245         return;
246
247     GraphicsLayer::setPreserves3D(b);
248     didChangeGeometry();
249 }
250
251 void WebGraphicsLayer::setMasksToBounds(bool b)
252 {
253     if (masksToBounds() == b)
254         return;
255     GraphicsLayer::setMasksToBounds(b);
256     didChangeGeometry();
257 }
258
259 void WebGraphicsLayer::setDrawsContent(bool b)
260 {
261     if (drawsContent() == b)
262         return;
263     GraphicsLayer::setDrawsContent(b);
264
265     didChangeLayerState();
266 }
267
268 void WebGraphicsLayer::setContentsOpaque(bool b)
269 {
270     if (contentsOpaque() == b)
271         return;
272     if (m_mainBackingStore)
273         m_mainBackingStore->setSupportsAlpha(!b);
274     GraphicsLayer::setContentsOpaque(b);
275     didChangeLayerState();
276 }
277
278 void WebGraphicsLayer::setBackfaceVisibility(bool b)
279 {
280     if (backfaceVisibility() == b)
281         return;
282
283     GraphicsLayer::setBackfaceVisibility(b);
284     didChangeLayerState();
285 }
286
287 void WebGraphicsLayer::setOpacity(float opacity)
288 {
289     if (this->opacity() == opacity)
290         return;
291
292     GraphicsLayer::setOpacity(opacity);
293     didChangeLayerState();
294 }
295
296 void WebGraphicsLayer::setContentsRect(const IntRect& r)
297 {
298     if (contentsRect() == r)
299         return;
300
301     GraphicsLayer::setContentsRect(r);
302     didChangeLayerState();
303 }
304
305 void WebGraphicsLayer::setContentsNeedsDisplay()
306 {
307     RefPtr<Image> image = m_image;
308     setContentsToImage(0);
309     setContentsToImage(image.get());
310 }
311
312 void WebGraphicsLayer::setContentsToImage(Image* image)
313 {
314     if (image == m_image)
315         return;
316     int64_t newID = 0;
317     if (m_webGraphicsLayerClient) {
318         // We adopt first, in case this is the same frame - that way we avoid destroying and recreating the image.
319         newID = m_webGraphicsLayerClient->adoptImageBackingStore(image);
320         m_webGraphicsLayerClient->releaseImageBackingStore(m_layerInfo.imageBackingStoreID);
321         didChangeLayerState();
322         if (m_layerInfo.imageBackingStoreID && newID == m_layerInfo.imageBackingStoreID)
323             return;
324     } else {
325         // If m_webGraphicsLayerClient is not set yet there should be no backing store ID.
326         ASSERT(!m_layerInfo.imageBackingStoreID);
327         didChangeLayerState();
328     }
329
330     m_layerInfo.imageBackingStoreID = newID;
331     m_image = image;
332     GraphicsLayer::setContentsToImage(image);
333 }
334
335 void WebGraphicsLayer::setMaskLayer(GraphicsLayer* layer)
336 {
337     if (layer == maskLayer())
338         return;
339
340     GraphicsLayer::setMaskLayer(layer);
341
342     if (!layer)
343         return;
344
345     layer->setSize(size());
346     WebGraphicsLayer* webGraphicsLayer = toWebGraphicsLayer(layer);
347     webGraphicsLayer->setWebGraphicsLayerClient(m_webGraphicsLayerClient);
348     webGraphicsLayer->setMaskTarget(this);
349     webGraphicsLayer->didChangeLayerState();
350     didChangeLayerState();
351
352 }
353
354 void WebGraphicsLayer::setReplicatedByLayer(GraphicsLayer* layer)
355 {
356     if (layer == replicaLayer())
357         return;
358
359     if (layer)
360         toWebGraphicsLayer(layer)->setWebGraphicsLayerClient(m_webGraphicsLayerClient);
361
362     GraphicsLayer::setReplicatedByLayer(layer);
363     didChangeLayerState();
364 }
365
366 void WebGraphicsLayer::setNeedsDisplay()
367 {
368     setNeedsDisplayInRect(IntRect(IntPoint::zero(), IntSize(size().width(), size().height())));
369 }
370
371 void WebGraphicsLayer::setNeedsDisplayInRect(const FloatRect& rect)
372 {
373     if (m_mainBackingStore)
374         m_mainBackingStore->invalidate(IntRect(rect));
375     didChangeLayerState();
376 }
377
378 WebLayerID WebGraphicsLayer::id() const
379 {
380     return m_id;
381 }
382
383 void WebGraphicsLayer::syncCompositingState(const FloatRect& rect)
384 {
385     if (WebGraphicsLayer* mask = toWebGraphicsLayer(maskLayer()))
386         mask->syncCompositingStateForThisLayerOnly();
387
388     if (WebGraphicsLayer* replica = toWebGraphicsLayer(replicaLayer()))
389         replica->syncCompositingStateForThisLayerOnly();
390
391     m_webGraphicsLayerClient->syncFixedLayers();
392
393     syncCompositingStateForThisLayerOnly();
394
395     for (size_t i = 0; i < children().size(); ++i)
396         children()[i]->syncCompositingState(rect);
397 }
398
399 WebGraphicsLayer* toWebGraphicsLayer(GraphicsLayer* layer)
400 {
401     return static_cast<WebGraphicsLayer*>(layer);
402 }
403
404 void WebGraphicsLayer::syncChildren()
405 {
406     if (!m_shouldSyncChildren)
407         return;
408     m_shouldSyncChildren = false;
409     Vector<WebLayerID> childIDs;
410     for (size_t i = 0; i < children().size(); ++i)
411         childIDs.append(toWebLayerID(children()[i]));
412
413     m_webGraphicsLayerClient->syncLayerChildren(m_id, childIDs);
414 }
415
416 void WebGraphicsLayer::syncLayerState()
417  {
418     if (!m_shouldSyncLayerState)
419         return;
420     m_shouldSyncLayerState = false;
421     m_layerInfo.fixedToViewport = fixedToViewport();
422
423     m_layerInfo.anchorPoint = anchorPoint();
424     m_layerInfo.backfaceVisible = backfaceVisibility();
425     m_layerInfo.childrenTransform = childrenTransform();
426     m_layerInfo.contentsOpaque = contentsOpaque();
427     m_layerInfo.contentsRect = contentsRect();
428     m_layerInfo.drawsContent = drawsContent();
429     m_layerInfo.mask = toWebLayerID(maskLayer());
430     m_layerInfo.masksToBounds = masksToBounds();
431     m_layerInfo.opacity = opacity();
432     m_layerInfo.parent = toWebLayerID(parent());
433     m_layerInfo.pos = position();
434     m_layerInfo.preserves3D = preserves3D();
435     m_layerInfo.replica = toWebLayerID(replicaLayer());
436     m_layerInfo.size = size();
437     m_layerInfo.transform = transform();
438     m_webGraphicsLayerClient->syncLayerState(m_id, m_layerInfo);
439 }
440
441 void WebGraphicsLayer::ensureImageBackingStore()
442 {
443     if (!m_image)
444         return;
445     if (!m_layerInfo.imageBackingStoreID)
446         m_layerInfo.imageBackingStoreID = m_webGraphicsLayerClient->adoptImageBackingStore(m_image.get());
447 }
448 void WebGraphicsLayer::syncCompositingStateForThisLayerOnly()
449 {
450     // The remote image might have been released by purgeBackingStores.
451     ensureImageBackingStore();
452     computeTransformedVisibleRect();
453     syncChildren();
454     syncLayerState();
455     updateContentBuffers();
456 }
457
458 void WebGraphicsLayer::tiledBackingStorePaintBegin()
459 {
460 }
461
462 void WebGraphicsLayer::setRootLayer(bool isRoot)
463 {
464     m_layerInfo.isRootLayer = isRoot;
465     didChangeLayerState();
466 }
467
468 void WebGraphicsLayer::setVisibleContentRectTrajectoryVector(const FloatPoint& trajectoryVector)
469 {
470     if (m_mainBackingStore)
471         m_mainBackingStore->coverWithTilesIfNeeded(trajectoryVector);
472 }
473
474 void WebGraphicsLayer::setContentsScale(float scale)
475 {
476     m_contentsScale = scale;
477     adjustContentsScale();
478 }
479
480 float WebGraphicsLayer::effectiveContentsScale()
481 {
482     return shouldUseTiledBackingStore() ? m_contentsScale : 1;
483 }
484
485 void WebGraphicsLayer::adjustContentsScale()
486 {
487     if (!drawsContent())
488         return;
489
490     if (!m_mainBackingStore || m_mainBackingStore->contentsScale() == effectiveContentsScale())
491         return;
492
493     // Between creating the new backing store and painting the content,
494     // we do not want to drop the previous one as that might result in
495     // briefly seeing flickering as the old tiles may be dropped before
496     // something replaces them.
497     m_previousBackingStore = m_mainBackingStore.release();
498
499     // No reason to save the previous backing store for non-visible areas.
500     m_previousBackingStore->removeAllNonVisibleTiles();
501
502     createBackingStore();
503 }
504
505 void WebGraphicsLayer::createBackingStore()
506 {
507     m_mainBackingStore = adoptPtr(new TiledBackingStore(this, TiledBackingStoreRemoteTileBackend::create(this)));
508     m_mainBackingStore->setSupportsAlpha(!contentsOpaque());
509     m_mainBackingStore->setContentsScale(effectiveContentsScale());
510 }
511
512 void WebGraphicsLayer::tiledBackingStorePaint(GraphicsContext* context, const IntRect& rect)
513 {
514     if (rect.isEmpty())
515         return;
516     paintGraphicsLayerContents(*context, rect);
517 }
518
519 void WebGraphicsLayer::tiledBackingStorePaintEnd(const Vector<IntRect>& updatedRects)
520 {
521 }
522
523 bool WebGraphicsLayer::tiledBackingStoreUpdatesAllowed() const
524 {
525     if (!m_inUpdateMode)
526         return false;
527     return m_webGraphicsLayerClient->layerTreeTileUpdatesAllowed();
528 }
529
530 IntRect WebGraphicsLayer::tiledBackingStoreContentsRect()
531 {
532     return IntRect(0, 0, size().width(), size().height());
533 }
534
535 bool WebGraphicsLayer::shouldUseTiledBackingStore()
536 {
537     return !selfOrAncestorHaveNonAffineTransforms();
538 }
539
540 IntRect WebGraphicsLayer::tiledBackingStoreVisibleRect()
541 {
542     if (!shouldUseTiledBackingStore())
543         return tiledBackingStoreContentsRect();
544
545     // Non-invertible layers are not visible.
546     if (!m_layerTransform.combined().isInvertible())
547         return IntRect();
548
549     // Return a projection of the visible rect (surface coordinates) onto the layer's plane (layer coordinates).
550     // The resulting quad might be squewed and the visible rect is the bounding box of this quad,
551     // so it might spread further than the real visible area (and then even more amplified by the cover rect multiplier).
552     return m_layerTransform.combined().inverse().clampedBoundsOfProjectedQuad(FloatQuad(FloatRect(m_webGraphicsLayerClient->visibleContentsRect())));
553 }
554
555 Color WebGraphicsLayer::tiledBackingStoreBackgroundColor() const
556 {
557     return contentsOpaque() ? Color::white : Color::transparent;
558 }
559
560 PassOwnPtr<WebCore::GraphicsContext> WebGraphicsLayer::beginContentUpdate(const WebCore::IntSize& size, ShareableSurface::Handle& handle, WebCore::IntPoint& offset)
561 {
562     return m_webGraphicsLayerClient->beginContentUpdate(size, contentsOpaque() ? 0 : ShareableBitmap::SupportsAlpha, handle, offset);
563 }
564
565 void WebGraphicsLayer::createTile(int tileID, const SurfaceUpdateInfo& updateInfo, const IntRect& targetRect)
566 {
567     m_webGraphicsLayerClient->createTile(id(), tileID, updateInfo, targetRect);
568 }
569
570 void WebGraphicsLayer::updateTile(int tileID, const SurfaceUpdateInfo& updateInfo, const IntRect& targetRect)
571 {
572     m_webGraphicsLayerClient->updateTile(id(), tileID, updateInfo, targetRect);
573 }
574
575 void WebGraphicsLayer::removeTile(int tileID)
576 {
577     m_webGraphicsLayerClient->removeTile(id(), tileID);
578 }
579
580 void WebGraphicsLayer::updateContentBuffers()
581 {
582     if (!drawsContent()) {
583         m_mainBackingStore.clear();
584         m_previousBackingStore.clear();
585         return;
586     }
587
588     m_inUpdateMode = true;
589     // This is the only place we (re)create the main tiled backing store, once we
590     // have a remote client and we are ready to send our data to the UI process.
591     if (!m_mainBackingStore)
592         createBackingStore();
593     m_mainBackingStore->updateTileBuffers();
594     m_inUpdateMode = false;
595
596     // The previous backing store is kept around to avoid flickering between
597     // removing the existing tiles and painting the new ones. The first time
598     // the visibleRect is full painted we remove the previous backing store.
599     if (m_mainBackingStore->visibleAreaIsCovered())
600         m_previousBackingStore.clear();
601 }
602
603 void WebGraphicsLayer::purgeBackingStores()
604 {
605     m_mainBackingStore.clear();
606     m_previousBackingStore.clear();
607
608     if (m_layerInfo.imageBackingStoreID) {
609         m_webGraphicsLayerClient->releaseImageBackingStore(m_layerInfo.imageBackingStoreID);
610         m_layerInfo.imageBackingStoreID = 0;
611     }
612 }
613
614 void WebGraphicsLayer::setWebGraphicsLayerClient(WebKit::WebGraphicsLayerClient* client)
615 {
616     if (m_webGraphicsLayerClient == client)
617         return;
618
619     if (WebGraphicsLayer* replica = toWebGraphicsLayer(replicaLayer()))
620         replica->setWebGraphicsLayerClient(client);
621     if (WebGraphicsLayer* mask = toWebGraphicsLayer(maskLayer()))
622         mask->setWebGraphicsLayerClient(client);
623     for (size_t i = 0; i < children().size(); ++i) {
624         WebGraphicsLayer* layer = toWebGraphicsLayer(this->children()[i]);
625         layer->setWebGraphicsLayerClient(client);
626     }
627
628     // We have to release resources on the UI process here if the remote client has changed or is removed.
629     if (m_webGraphicsLayerClient) {
630         purgeBackingStores();
631         m_webGraphicsLayerClient->detachLayer(this);
632     }
633     m_webGraphicsLayerClient = client;
634     if (client)
635         client->attachLayer(this);
636 }
637
638 void WebGraphicsLayer::adjustVisibleRect()
639 {
640     if (m_mainBackingStore)
641         m_mainBackingStore->coverWithTilesIfNeeded();
642 }
643
644 void WebGraphicsLayer::computeTransformedVisibleRect()
645 {
646     if (!m_shouldUpdateVisibleRect)
647         return;
648     m_shouldUpdateVisibleRect = false;
649     m_layerTransform.setLocalTransform(transform());
650     m_layerTransform.setPosition(position());
651     m_layerTransform.setAnchorPoint(anchorPoint());
652     m_layerTransform.setSize(size());
653     m_layerTransform.setFlattening(!preserves3D());
654     m_layerTransform.setChildrenTransform(childrenTransform());
655     m_layerTransform.combineTransforms(parent() ? toWebGraphicsLayer(parent())->m_layerTransform.combinedForChildren() : TransformationMatrix());
656
657     // The combined transform will be used in tiledBackingStoreVisibleRect.
658     adjustVisibleRect();
659     adjustContentsScale();
660 }
661
662 static PassOwnPtr<GraphicsLayer> createWebGraphicsLayer(GraphicsLayerClient* client)
663 {
664     return adoptPtr(new WebGraphicsLayer(client));
665 }
666
667 void WebGraphicsLayer::initFactory()
668 {
669     GraphicsLayer::setGraphicsLayerFactory(createWebGraphicsLayer);
670 }
671
672 bool WebGraphicsLayer::selfOrAncestorHaveNonAffineTransforms()
673 {
674     if (!m_layerTransform.combined().isAffine())
675         return true;
676
677     return false;
678 }
679
680 }
681 #endif