Reviewed by Hyatt
[WebKit-https.git] / WebCore / loader / icon / IconDataCache.cpp
1 /*
2  * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27 #include "IconDataCache.h"
28
29 #include "Logging.h"
30 #include "Image.h"
31 #include <limits.h>
32 #include "SQLStatement.h"
33
34
35 namespace WebCore {
36
37 IconDataCache::IconDataCache(const String& url)
38     : m_iconURL(url)
39     , m_stamp(0)
40     , m_image(0)
41     , m_dataSet(false)
42 {
43
44 }
45
46 IconDataCache::~IconDataCache()
47 {
48     // Upon destruction of a IconDataCache, its image should no longer be in use anywhere
49     delete m_image;
50 }
51
52 Image* IconDataCache::getImage(const IntSize& size)
53 {
54     // FIXME rdar://4680377 - For size right now, we are returning our one and only image and the Bridge
55     // is resizing it in place.  We need to actually store all the original representations here and return a native
56     // one, or resize the best one to the requested size and cache that result.
57     if (m_image)
58         return m_image;
59     
60     return 0;
61 }
62
63 void IconDataCache::setImageData(unsigned char* data, int size)
64 {
65     if (!data)
66         ASSERT(!size);
67
68     // It's okay to delete the raw image data here. Any existing clients using this icon will be
69     // managing an image that was created with a copy of this raw image data.
70     if (m_image)
71         delete m_image;
72     m_image = new Image();
73
74     // Copy the provided data into the buffer of the new Image object
75     Vector<char>& dataBuffer = m_image->dataBuffer();
76     dataBuffer.resize(size);
77     memcpy(dataBuffer.data(), data, size);
78     
79     // Tell the Image object that all of its data has been set
80     if (!m_image->setData(true)) {
81         LOG(IconDatabase, "Manual image data for iconURL '%s' FAILED - it was probably invalid image data", m_iconURL.ascii().data());
82         delete m_image;
83         m_image = 0;
84     }
85     
86     m_dataSet = true;
87 }
88
89 void IconDataCache::loadImageFromResource(const char* resource)
90 {
91     if (!resource)
92         return;
93     delete m_image;
94     m_image = Image::loadPlatformResource(resource);
95     m_dataSet = true;
96 }
97
98 void IconDataCache::writeToDatabase(SQLDatabase& db)
99 {
100     if (m_iconURL.isEmpty())
101         return;
102     
103     // First we'll try an update in case we're already in the DB
104     SQLStatement updateAttempt(db, "UPDATE Icon SET stamp = ?, data = ? WHERE url = ?;");
105     updateAttempt.prepare();
106     
107     // Bind the url and timestamp
108     updateAttempt.bindInt64(1, m_stamp);
109     updateAttempt.bindText16(3, m_iconURL);
110     
111     // If we *have* image data, bind it to this statement - Otherwise the DB will get "null" for the blob data, 
112     // signifying that this icon doesn't have any data    
113     if (m_image && !m_image->dataBuffer().isEmpty())
114         updateAttempt.bindBlob(2, m_image->dataBuffer().data(), m_image->dataBuffer().size());
115     
116     if (updateAttempt.step() != SQLITE_DONE) {
117         LOG_ERROR("Failed to update icon data for IconURL %s", m_iconURL.ascii().data());
118         return;
119     }
120     
121     // If the UPDATE command actually altered a row, we're done
122     if (db.lastChanges())
123         return;
124         
125         
126     // Otherwise, we've never inserted this Icon URL before, so we'll do so now
127     updateAttempt.finalize();
128     SQLStatement insertStatement(db, "INSERT INTO Icon (url,stamp,data) VALUES (?, ?, ?);");
129     insertStatement.prepare();
130         
131     // Bind the url and timestamp
132     insertStatement.bindText16(1, m_iconURL);
133     insertStatement.bindInt64(2, m_stamp);
134         
135     // Then, if we *have* data, we bind it.  Otherwise the DB will get "null" for the blob data, 
136     // signifying that this icon doesn't have any data
137     if (m_image && !m_image->dataBuffer().isEmpty())
138         insertStatement.bindBlob(3, m_image->dataBuffer().data(), m_image->dataBuffer().size());
139     
140     // Finally we step and make sure the step was successful
141     if (insertStatement.step() != SQLITE_DONE)
142         LOG_ERROR("Unable to set icon data for IconURL %s", m_iconURL.ascii().data());
143 }
144
145 ImageDataStatus IconDataCache::imageDataStatus()
146 {
147     if (!m_dataSet)
148         return ImageDataStatusUnknown;
149     if (!m_image)
150         return ImageDataStatusMissing;
151     return ImageDataStatusPresent;
152 }
153
154 } // namespace WebCore