130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun/* 230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * Copyright 2011 Google Inc. All Rights Reserved. 330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * 430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * Licensed under the Apache License, Version 2.0 (the "License"); 530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * you may not use this file except in compliance with the License. 630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * You may obtain a copy of the License at 730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * 830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * http://www.apache.org/licenses/LICENSE-2.0 930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * 1030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * Unless required by applicable law or agreed to in writing, software 1130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * distributed under the License is distributed on an "AS IS" BASIS, 1230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * See the License for the specific language governing permissions and 1430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * limitations under the License. 1530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun */ 1630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 1730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "sfntly/table/font_data_table.h" 1830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 1930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#include "sfntly/data/font_output_stream.h" 2030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 2130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunnamespace sfntly { 2230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 2330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun/****************************************************************************** 2430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * FontDataTable class 2530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun ******************************************************************************/ 2630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 2730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim GurunFontDataTable::FontDataTable(ReadableFontData* data) { 2830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun data_ = data; 2930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun} 3030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 3130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim GurunFontDataTable::~FontDataTable() {} 3230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 3330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim GurunReadableFontData* FontDataTable::ReadFontData() { 3430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun return data_; 3530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun} 3630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 3730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunint32_t FontDataTable::DataLength() { 3830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun return data_->Length(); 3930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun} 4030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 4130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunint32_t FontDataTable::Serialize(OutputStream* os) { 4230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun return data_->CopyTo(os); 4330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun} 4430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 4530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunint32_t FontDataTable::Serialize(WritableFontData* data) { 4630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun return data_->CopyTo(data); 4730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun} 4830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 4930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun/****************************************************************************** 5030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun * FontDataTable::Builder class 5130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun ******************************************************************************/ 5230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim GurunCALLER_ATTACH WritableFontData* FontDataTable::Builder::Data() { 5330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun WritableFontDataPtr new_data; 5430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun if (model_changed_) { 5530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun if (!SubReadyToSerialize()) { 5630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#if !defined (SFNTLY_NO_EXCEPTION) 5730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun throw IOException("Table not ready to build."); 5830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#endif 5930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun return NULL; 6030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 6130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun int32_t size = SubDataSizeToSerialize(); 6230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun new_data.Attach(WritableFontData::CreateWritableFontData(size)); 6330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun SubSerialize(new_data); 6430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } else { 6530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun ReadableFontDataPtr data = InternalReadData(); 6630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun new_data.Attach(WritableFontData::CreateWritableFontData( 6730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun data != NULL ? data->Length() : 0)); 6830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun if (data != NULL) { 6930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun data->CopyTo(new_data); 7030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 7130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 7230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun return new_data.Detach(); 7330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun} 7430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 7530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunvoid FontDataTable::Builder::SetData(ReadableFontData* data) { 7630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun InternalSetData(data, true); 7730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun} 7830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 7930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 8030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim GurunCALLER_ATTACH FontDataTable* FontDataTable::Builder::Build() { 8130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun FontDataTablePtr table; // NULL default table 8230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun ReadableFontDataPtr data = InternalReadData(); 8330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun if (model_changed_) { 8430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun // Let subclass serialize from model. 8530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun if (!SubReadyToSerialize()) { 8630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#if !defined (SFNTLY_NO_EXCEPTION) 8730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun throw IOException("Table not ready to build."); 8830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#endif 8930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun return NULL; 9030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 9130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun int32_t size = SubDataSizeToSerialize(); 9230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun WritableFontDataPtr new_data; 9330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun new_data.Attach(WritableFontData::CreateWritableFontData(size)); 9430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun SubSerialize(new_data); 9530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun data = new_data; 9630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 9730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 9830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun if (data != NULL) { 9930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun table = SubBuildTable(data); 10030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun NotifyPostTableBuild(table); 10130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 10230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 10330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun r_data_.Release(); 10430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun w_data_.Release(); 10530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun return table; 10630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun} 10730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 10830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunbool FontDataTable::Builder::ReadyToBuild() { 10930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun return true; 11030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun} 11130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 11230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim GurunReadableFontData* FontDataTable::Builder::InternalReadData() { 11330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun return (r_data_ != NULL) ? r_data_.p_ : 11430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun static_cast<ReadableFontData*>(w_data_.p_); 11530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun} 11630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 11730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim GurunWritableFontData* FontDataTable::Builder::InternalWriteData() { 11830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun if (w_data_ == NULL) { 11930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun WritableFontDataPtr new_data; 12030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun new_data.Attach(WritableFontData::CreateWritableFontData( 12130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun r_data_ == NULL ? 0 : r_data_->Length())); 12230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#if !defined (SFNTLY_NO_EXCEPTION) 12330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun try { 12430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#endif 12530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun if (r_data_) { 12630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun r_data_->CopyTo(new_data); 12730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 12830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#if !defined (SFNTLY_NO_EXCEPTION) 12930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } catch (IOException& e) { 13030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun // TODO(stuartg): fix when IOExceptions are cleaned up 13130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 13230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun#endif 13330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun InternalSetData(new_data, false); 13430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 13530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun return w_data_.p_; 13630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun} 13730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 13830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim GurunFontDataTable::Builder::Builder() 13930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun : model_changed_(false), 14030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun contained_model_changed_(false), 14130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun data_changed_(false) { 14230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun} 14330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 14430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim GurunFontDataTable::Builder::Builder(int32_t data_size) 14530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun : model_changed_(false), 14630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun contained_model_changed_(false), 14730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun data_changed_(false) { 14830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun w_data_.Attach(WritableFontData::CreateWritableFontData(data_size)); 14930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun} 15030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 15130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim GurunFontDataTable::Builder::Builder(WritableFontData* data) 15230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun : model_changed_(false), 15330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun contained_model_changed_(false), 15430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun data_changed_(false) { 15530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun w_data_ = data; 15630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun} 15730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 15830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim GurunFontDataTable::Builder::Builder(ReadableFontData* data) 15930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun : model_changed_(false), 16030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun contained_model_changed_(false), 16130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun data_changed_(false) { 16230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun r_data_ = data; 16330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun} 16430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 16530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim GurunFontDataTable::Builder::~Builder() { 16630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun} 16730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 16830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunvoid FontDataTable::Builder::NotifyPostTableBuild(FontDataTable* table) { 16930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun // Default: NOP. 17030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun UNREFERENCED_PARAMETER(table); 17130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun} 17230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 17330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunvoid FontDataTable::Builder::InternalSetData(WritableFontData* data, 17430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun bool data_changed) { 17530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun w_data_ = data; 17630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun r_data_ = NULL; 17730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun if (data_changed) { 17830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun data_changed_ = true; 17930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun SubDataSet(); 18030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 18130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun} 18230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 18330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurunvoid FontDataTable::Builder::InternalSetData(ReadableFontData* data, 18430d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun bool data_changed) { 18530d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun w_data_ = NULL; 18630d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun r_data_ = data; 18730d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun if (data_changed) { 18830d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun data_changed_ = true; 18930d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun SubDataSet(); 19030d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun } 19130d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun} 19230d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun 19330d4e1f3d81ad9f7a1aa14ce6d2ceb5df56c15cdSelim Gurun} // namespace sfntly 194